Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] 코스 발견 / 추천 코스 정렬 기능 #313

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f7a0a07
[FEAT] #307 정렬 버튼을 클릭하면 해당 기준으로 서버에 추천 코스 리스트를 요청하는 코드 추가
leeeha Jan 6, 2024
98fbf91
[MOD] #308 마라톤, 추천 코스 조회 로직 수정
leeeha Jan 6, 2024
23cd32a
[MERGE] #307 브랜치 병합
leeeha Jan 6, 2024
2b8b8d9
[FEAT] #307 정렬된 리스트로 추천 코스 목록 전체를 갱신하고, 어댑터에 notify 하도록 구현
leeeha Jan 6, 2024
2ce1684
[MOD] #307 첫 페이지를 조회하는 함수의 인자 변경
leeeha Jan 6, 2024
724d0a5
[FEAT] #307 RecommendCourseViewHolder 안에서 정렬 버튼 클릭 리스너 정의
leeeha Jan 6, 2024
5f59dc4
[CHORE] #307 로그 메시지 추가
leeeha Jan 6, 2024
4e22b9d
[UI] #307 정렬 버튼 클릭에 따라 텍스트 스타일 변경
leeeha Jan 6, 2024
dc8d064
[FIX] #308 추천 코스까지 모두 로딩되었을 때만 canScrollVertically 함수가 실행되도록 변경
leeeha Jan 6, 2024
b2dff9b
Merge branch 'feature/fix-multiview-recyclerview-loading' of https://…
leeeha Jan 6, 2024
1e1ed07
[MOD] #307 추천 코스 영역을 헤더와 코스 부분으로 타입 분리하기
leeeha Jan 7, 2024
7e742e0
[FIX] #307 정렬 기준을 전환할 때마다 페이지 번호도 1로 초기화 하도록 변경
leeeha Jan 7, 2024
b859b10
[FIX] #308 외부 리사이클러뷰의 어댑터가 초기화 되었는지 검사하는 코드 추가
leeeha Jan 7, 2024
76dc6be
Merge branch 'feature/fix-multiview-recyclerview-loading' of https://…
leeeha Jan 7, 2024
55a8f18
[DEL] #307 불필요한 주석 삭제
leeeha Jan 7, 2024
6bfd6b1
[CHORE] #307 추천 코스 페이지 관련 데이터 초기화 하는 함수명 변경
leeeha Jan 7, 2024
75d7215
[FIX] #308 마라톤 코스 조회에 성공한 경우에만 추천 코스 옵저버 실행
leeeha Jan 9, 2024
3cc4704
[FEAT] #308 멀티뷰 아이템 클래스에 viewType 반환하는 함수 정의
leeeha Jan 10, 2024
ddb4f9e
Merge branch 'develop' of https://github.com/Runnect/Runnect-Android …
leeeha Jan 10, 2024
9a00970
[MOD] #308 멀티뷰 어댑터 내부에서만 mutable 하도록 2차원 리스트 타입 변경
leeeha Jan 12, 2024
b7ac4d4
[MOD] #308 getItemViewType 함수 내용 변경
leeeha Jan 12, 2024
efd2e3c
[MOD] #308 멀티뷰 아이템 리스트가 비어있는 경우에는 어떤 데이터도 뷰에 바인딩 하지 않도록 구현
leeeha Jan 12, 2024
71e4ab8
[MOD] #308 비어있는 리스트로 멀티뷰 어댑터 초기화 하도록 변경
leeeha Jan 12, 2024
37a04f1
[CHORE] #308 리사이클러뷰 초기화 하는 함수의 선언 위치 변경
leeeha Jan 12, 2024
0731708
[MOD] #308 리프레시 하면 멀티뷰 어댑터의 데이터 목록 모두 삭제하도록 변경
leeeha Jan 12, 2024
6f3691f
[MOD] #308 getRecommendCourses 함수의 인자 변경
leeeha Jan 12, 2024
2ac852f
[FIX] #308 마라톤 코스 아이템 데코레이션 한번만 적용하도록 변경
leeeha Jan 12, 2024
07873d5
[MOD] #308 생성자에서 데이터 목록을 받도록 멀티뷰 어댑터 코드 변경
leeeha Jan 16, 2024
75c015f
[MOD] #308 뷰홀더 생성하는 함수에서 인자의 타입 변경
leeeha Jan 16, 2024
42da096
[MOD] #308 마라톤 코스에 의해 리사이클러뷰 어댑터 초기화 되면 추천 코스 리스트 추가
leeeha Jan 16, 2024
1bae106
[MOD] #308 가독성을 위해 코드 흐름에 따라 함수의 선언 위치 변경
leeeha Jan 16, 2024
f4985c4
[MOD] #307 마라톤 코스로 리사이클러뷰 어댑터 초기화 한 다음 추천 코스 목록 추가하도록 변경
leeeha Jan 16, 2024
5753c59
Merge branch 'feature/fix-multiview-recyclerview-loading' of https://…
leeeha Jan 16, 2024
8344cac
[DEL] #307 refresh 하면 새로운 리스트로 초기화 되므로 clear 함수 삭제
leeeha Jan 16, 2024
9540728
[FIX] #307 정렬에 사용되는 인자 이름 변경
leeeha Jan 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ class CourseRepositoryImpl @Inject constructor(private val remoteCourseDataSourc

override suspend fun getRecommendCourse(
pageNo: String,
ordering: String
sort: String
): Result<RecommendCoursePagingData?> = runCatching {
val response = remoteCourseDataSource.getRecommendCourse(
pageNo = pageNo,
ordering = ordering
sort = sort
).data

response?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ interface CourseService {
@GET("/api/public-course")
suspend fun getRecommendCourse(
@Query("pageNo") pageNo: String,
@Query("ordering") ordering: String
@Query("sort") sort: String
): BaseResponse<ResponseGetDiscoverRecommend>

@POST("/api/scrap")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ class RemoteCourseDataSource @Inject constructor(

suspend fun getRecommendCourse(
pageNo: String,
ordering: String
sort: String
): BaseResponse<ResponseGetDiscoverRecommend> =
courseService.getRecommendCourse(pageNo = pageNo, ordering = ordering)
courseService.getRecommendCourse(pageNo = pageNo, sort = sort)

suspend fun postCourseScrap(requestPostCourseScrap: RequestPostCourseScrap): BaseResponse<ResponsePostScrap> =
courseService.postCourseScrap(requestPostCourseScrap)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.runnect.runnect.domain.entity

import com.runnect.runnect.presentation.discover.adapter.multiview.DiscoverMultiViewType
import com.runnect.runnect.presentation.discover.adapter.multiview.DiscoverMultiViewType.*

sealed class DiscoverMultiViewItem(
private val viewType: DiscoverMultiViewType,
open val id: Int
) {
data class MarathonCourse(
Expand All @@ -10,7 +14,13 @@ sealed class DiscoverMultiViewItem(
val image: String,
var scrap: Boolean,
val departure: String,
) : DiscoverMultiViewItem(id)
) : DiscoverMultiViewItem(MARATHON, id)

data class RecommendHeader(
override val id: Int,
val title: String,
val subtitle: String
): DiscoverMultiViewItem(RECOMMEND_HEADER, id)

data class RecommendCourse(
override val id: Int,
Expand All @@ -19,5 +29,7 @@ sealed class DiscoverMultiViewItem(
val image: String,
var scrap: Boolean,
val departure: String,
) : DiscoverMultiViewItem(id)
) : DiscoverMultiViewItem(RECOMMEND_COURSE, id)

fun getMultiViewType() = viewType
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ interface CourseRepository {

suspend fun getRecommendCourse(
pageNo: String,
ordering: String
sort: String
): Result<RecommendCoursePagingData?>

suspend fun getCourseSearch(keyword: String): Result<List<DiscoverSearchCourse>?>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ class MainActivity : BindingActivity<ActivityMainBinding>(R.layout.activity_main
var storageScrapFragment: StorageScrapFragment? = null

fun updateCourseDiscoverScreen() {
discoverFragment?.getRecommendCourses(pageNo = 1)
discoverFragment?.getRecommendCourses()
}

fun updateStorageScrapScreen() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ import com.runnect.runnect.R
import com.runnect.runnect.binding.BindingFragment
import com.runnect.runnect.databinding.FragmentDiscoverBinding
import com.runnect.runnect.domain.entity.DiscoverBanner
import com.runnect.runnect.domain.entity.DiscoverMultiViewItem
import com.runnect.runnect.presentation.discover.model.EditableDiscoverCourse
import com.runnect.runnect.presentation.MainActivity
import com.runnect.runnect.presentation.MainActivity.Companion.isVisitorMode
import com.runnect.runnect.presentation.detail.CourseDetailActivity
import com.runnect.runnect.presentation.detail.CourseDetailRootScreen
import com.runnect.runnect.presentation.discover.adapter.BannerAdapter
import com.runnect.runnect.presentation.discover.adapter.multiview.DiscoverMultiViewAdapter
import com.runnect.runnect.presentation.discover.adapter.multiview.DiscoverMultiViewType
import com.runnect.runnect.presentation.discover.pick.DiscoverPickActivity
import com.runnect.runnect.presentation.discover.search.DiscoverSearchActivity
import com.runnect.runnect.presentation.state.UiStateV2
Expand Down Expand Up @@ -60,6 +62,7 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
val updatedCourse: EditableDiscoverCourse =
result.data?.getCompatibleParcelableExtra(EXTRA_EDITABLE_DISCOVER_COURSE)
?: return@registerForActivityResult

multiViewAdapter.updateCourseItem(
publicCourseId = viewModel.clickedCourseId,
updatedCourse = updatedCourse
Expand Down Expand Up @@ -96,7 +99,6 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
Timber.d("viewpager position: $position")
updateBannerPosition(position)
updateBannerIndicatorPosition()
}
Expand Down Expand Up @@ -155,18 +157,16 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
}

private fun checkNextPageLoadingCondition(recyclerView: RecyclerView) {
if (!recyclerView.canScrollVertically(SCROLL_DIRECTION)) {
if (isCourseLoadingCompleted() && !recyclerView.canScrollVertically(SCROLL_DIRECTION)) {
Timber.d("스크롤이 끝에 도달했어요!")

if (viewModel.isNextPageLoading()) {
Timber.d("다음 페이지 로딩 중입니다.")
return
}

if (viewModel.isNextPageLoading()) return
viewModel.getRecommendCourseNextPage()
}
}

private fun isCourseLoadingCompleted() = ::multiViewAdapter.isInitialized &&
multiViewAdapter.itemCount >= DiscoverMultiViewType.values().size

private fun showCircleUploadButton() {
binding.fabDiscoverUploadText.isVisible = false
binding.fabDiscoverUpload.isVisible = true
Expand All @@ -186,7 +186,6 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm

private fun initRefreshLayoutListener() {
binding.refreshLayout.setOnRefreshListener {
viewModel.resetMultiViewItems()
viewModel.refreshCurrentCourses()
binding.refreshLayout.isRefreshing = false
}
Expand Down Expand Up @@ -230,7 +229,7 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
private fun addObserver() {
setupBannerGetStateObserver()
setupMarathonCourseGetStateObserver()
setupRecommendCourseGetStateObserver()
setupRecommendCourseSortStateObserver()
setupRecommendCourseNextPageStateObserver()
setupCourseScrapStateObserver()
}
Expand Down Expand Up @@ -292,35 +291,19 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
}

private fun setupMarathonCourseGetStateObserver() {
viewModel.marathonCourseState.observe(viewLifecycleOwner) { state ->
viewModel.marathonCourseGetState.observe(viewLifecycleOwner) { state ->
when (state) {
is UiStateV2.Loading -> showLoadingProgressBar()

is UiStateV2.Failure -> {
is UiStateV2.Success -> {
dismissLoadingProgressBar()
context?.showSnackbar(
anchorView = binding.root,
message = state.msg,
gravity = Gravity.TOP
)
}

else -> {}
}
}
}

private fun setupRecommendCourseGetStateObserver() {
viewModel.recommendCourseState.observe(viewLifecycleOwner) { state ->
when (state) {
is UiStateV2.Loading -> showLoadingProgressBar()
// 외부 리사이클러뷰 어댑터 초기화
initMultiViewAdapter(createMultiViewItems(state.data))
initMultiRecyclerView()

is UiStateV2.Success -> {
if (viewModel.checkCourseLoadState()) {
dismissLoadingProgressBar()
initMultiViewAdapter()
initMultiRecyclerView()
}
// 어댑터에 추천 코스 목록 추가
setupRecommendCourseGetStateObserver()
}

is UiStateV2.Failure -> {
Expand All @@ -337,6 +320,20 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
}
}

private fun createMultiViewItems(courses: List<DiscoverMultiViewItem>) =
mutableListOf<List<DiscoverMultiViewItem>>().apply {
add(courses)
add(
listOf(
DiscoverMultiViewItem.RecommendHeader(
id = RECOMMEND_HEADER_INDEX,
title = getString(R.string.discover_recommend_header_title),
subtitle = getString(R.string.discover_recommend_header_subtitle)
)
)
)
}

private fun showLoadingProgressBar() {
binding.rvDiscoverMultiView.isVisible = false
binding.pbDiscoverLoading.isVisible = true
Expand All @@ -347,18 +344,25 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
binding.pbDiscoverLoading.isVisible = false
}

private fun initMultiViewAdapter() {
private fun initMultiViewAdapter(multiViewItems: List<List<DiscoverMultiViewItem>>) {
multiViewAdapter = DiscoverMultiViewAdapter(
multiViewItems = viewModel.multiViewItems,
multiViewItems = multiViewItems,
onHeartButtonClick = { courseId, scrap ->
viewModel.postCourseScrap(courseId, scrap)
viewModel.postCourseScrap(
id = courseId,
scrapTF = scrap
)
},
onCourseItemClick = { courseId ->
navigateToDetailScreen(courseId)
viewModel.saveClickedCourseId(courseId)
navigateToDetailScreen(publicCourseId = courseId)
viewModel.saveClickedCourseId(id = courseId)
},
handleVisitorMode = {
context?.let { showCourseScrapWarningToast(it) }
},
onSortButtonClick = { criteria ->
Timber.d("정렬 기준: $criteria")
viewModel.sortRecommendCourses(criteria = criteria)
}
)
}
Expand Down Expand Up @@ -387,12 +391,53 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
).show()
}

private fun setupRecommendCourseGetStateObserver() {
viewModel.recommendCourseGetState.observe(viewLifecycleOwner) { state ->
when (state) {
is UiStateV2.Success -> {
multiViewAdapter.addMultiViewItem(state.data)
viewModel.initRecommendCourseGetState()
}

is UiStateV2.Failure -> {
context?.showSnackbar(
Copy link
Contributor

Choose a reason for hiding this comment

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

requireContext를 사용해보시는 건 어떨까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

안녕하세요 지훈님! 리뷰 남겨주셔서 감사합니다 😄

requireContext를 사용하지 않은 이유는 여기 노션 문서를 참고해주세요!

anchorView = binding.root,
message = state.msg,
gravity = Gravity.TOP
)
}

else -> {}
}
}
}

private fun setupRecommendCourseSortStateObserver() {
viewModel.recommendCourseSortState.observe(viewLifecycleOwner) { state ->
when (state) {
is UiStateV2.Success -> {
// 추천 코스 목록 전체 갱신
multiViewAdapter.updateRecommendCourseBySorting(state.data)
}

is UiStateV2.Failure -> {
context?.showSnackbar(
anchorView = binding.root,
message = state.msg,
gravity = Gravity.TOP
)
}

else -> {}
}
}
}

private fun setupRecommendCourseNextPageStateObserver() {
viewModel.nextPageState.observe(viewLifecycleOwner) { state ->
viewModel.recommendCourseNextPageState.observe(viewLifecycleOwner) { state ->
when (state) {
is UiStateV2.Success -> {
val nextPageCourses = state.data
multiViewAdapter.addRecommendCourseNextPage(nextPageCourses)
multiViewAdapter.addRecommendCourseNextPage(state.data)
}

is UiStateV2.Failure -> {
Expand Down Expand Up @@ -449,8 +494,8 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
return layoutManager.findFirstCompletelyVisibleItemPosition() > 0
}

fun getRecommendCourses(pageNo: Int) {
viewModel.getRecommendCourse(pageNo = pageNo, ordering = "date")
fun getRecommendCourses() {
viewModel.getRecommendCourses()
}

override fun onAttach(context: Context) {
Expand All @@ -469,6 +514,7 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
private const val BANNER_SCROLL_DELAY_TIME = 5000L
private const val CENTER_POS_OF_INFINITE_BANNERS = Int.MAX_VALUE / 2
private const val SCROLL_DIRECTION = 1
private const val RECOMMEND_HEADER_INDEX = -1
private const val EXTRA_PUBLIC_COURSE_ID = "publicCourseId"
private const val EXTRA_ROOT_SCREEN = "rootScreen"
const val EXTRA_EDITABLE_DISCOVER_COURSE = "editable_discover_course"
Expand Down
Loading
Loading