From 6c7b5d35dd393beff34e24873bf4a0108dc31998 Mon Sep 17 00:00:00 2001 From: leeseokchan00 <112953135+leeseokchan00@users.noreply.github.com> Date: Tue, 29 Oct 2024 03:27:28 +0900 Subject: [PATCH 1/7] [feat] #178 recent clip ui --- .../main/res/drawable/ic_arrow_black_svg.xml | 13 ++ .../drawable/shape_grey900_fill_8_rect.xml | 0 .../res/drawable/shape_red_fill_8_rect.xml | 0 .../src/main/res/values/strings.xml | 2 +- .../main/java/org/sopt/home/HomeContract.kt | 1 + .../main/java/org/sopt/home/HomeFragment.kt | 13 ++ .../main/java/org/sopt/home/HomeViewModel.kt | 1 + .../home/viewholder/HomeClipViewHolder.kt | 23 +-- .../src/main/res/layout/fragment_home.xml | 18 ++- .../src/main/res/layout/item_home_clip.xml | 148 +++++++++--------- 10 files changed, 120 insertions(+), 99 deletions(-) create mode 100644 core/designsystem/src/main/res/drawable/ic_arrow_black_svg.xml rename {feature/clip => core/designsystem}/src/main/res/drawable/shape_grey900_fill_8_rect.xml (100%) rename {feature/clip => core/designsystem}/src/main/res/drawable/shape_red_fill_8_rect.xml (100%) diff --git a/core/designsystem/src/main/res/drawable/ic_arrow_black_svg.xml b/core/designsystem/src/main/res/drawable/ic_arrow_black_svg.xml new file mode 100644 index 00000000..6b5550e9 --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_arrow_black_svg.xml @@ -0,0 +1,13 @@ + + + diff --git a/feature/clip/src/main/res/drawable/shape_grey900_fill_8_rect.xml b/core/designsystem/src/main/res/drawable/shape_grey900_fill_8_rect.xml similarity index 100% rename from feature/clip/src/main/res/drawable/shape_grey900_fill_8_rect.xml rename to core/designsystem/src/main/res/drawable/shape_grey900_fill_8_rect.xml diff --git a/feature/clip/src/main/res/drawable/shape_red_fill_8_rect.xml b/core/designsystem/src/main/res/drawable/shape_red_fill_8_rect.xml similarity index 100% rename from feature/clip/src/main/res/drawable/shape_red_fill_8_rect.xml rename to core/designsystem/src/main/res/drawable/shape_red_fill_8_rect.xml diff --git a/core/designsystem/src/main/res/values/strings.xml b/core/designsystem/src/main/res/values/strings.xml index a22fe03d..64cb89ff 100644 --- a/core/designsystem/src/main/res/values/strings.xml +++ b/core/designsystem/src/main/res/values/strings.xml @@ -152,7 +152,7 @@ 잊지 않고 읽었어요! nn /nn - 님의 클립 + 님이 최근 저장한 링크 이주의 링크 이주의 추천 사이트 diff --git a/feature/home/src/main/java/org/sopt/home/HomeContract.kt b/feature/home/src/main/java/org/sopt/home/HomeContract.kt index 797a17cf..1ea351de 100644 --- a/feature/home/src/main/java/org/sopt/home/HomeContract.kt +++ b/feature/home/src/main/java/org/sopt/home/HomeContract.kt @@ -29,6 +29,7 @@ sealed interface HomeSideEffect { data object NavigateSetting : HomeSideEffect data object NavigateSearch : HomeSideEffect data object NavigateClipLink : HomeSideEffect + data object NavigateAllClip : HomeSideEffect data object NavigateWebView : HomeSideEffect data object ShowBottomSheet : HomeSideEffect } diff --git a/feature/home/src/main/java/org/sopt/home/HomeFragment.kt b/feature/home/src/main/java/org/sopt/home/HomeFragment.kt index 70926045..15f44492 100644 --- a/feature/home/src/main/java/org/sopt/home/HomeFragment.kt +++ b/feature/home/src/main/java/org/sopt/home/HomeFragment.kt @@ -33,6 +33,7 @@ class HomeFragment : BindingFragment({ FragmentHomeBinding. collectState() navigateToSetting() navigateToSearch() + navigateToAllClip() } private fun initView() { @@ -69,6 +70,7 @@ class HomeFragment : BindingFragment({ FragmentHomeBinding. "featureSaveLink://webViewFragment/${0}/${false}/${false}/$encodedURL", ) } + is HomeSideEffect.NavigateAllClip -> navigateToClip() } } @@ -94,6 +96,12 @@ class HomeFragment : BindingFragment({ FragmentHomeBinding. } } + private fun navigateToAllClip(){ + binding.ivRecentClip.onThrottleClick { + viewModel.navigateAllClip() + } + } + private fun setClipAdapter() { homeClipAdapter = HomeClipAdapter( onClickClip = { @@ -139,6 +147,11 @@ class HomeFragment : BindingFragment({ FragmentHomeBinding. findNavController().navigate(request, navOptions) } + private fun navigateToClip(){ + val (request, navOptions) = DeepLinkUtil.getNavRequestNotPopUpAndOption("featureSaveLink://ClipLinkFragment/0/전체 클립") + findNavController().navigate(request, navOptions) + } + private fun showHomeBottomSheet() { val linkMindBottomSheet = LinkMindBottomSheet(requireContext()) linkMindBottomSheet.show() diff --git a/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt b/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt index 9326aa7f..22b73263 100644 --- a/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt +++ b/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt @@ -89,6 +89,7 @@ class HomeViewModel @Inject constructor( fun navigateSearch() = intent { postSideEffect(HomeSideEffect.NavigateSearch) } fun navigateSetting() = intent { postSideEffect(HomeSideEffect.NavigateSetting) } fun showBottomSheet() = intent { postSideEffect(HomeSideEffect.ShowBottomSheet) } + fun navigateAllClip() = intent { postSideEffect(HomeSideEffect.NavigateAllClip) } @OptIn(OrbitExperimental::class) fun navigateClipLink(categoryId: Long?, categoryName: String?) = blockingIntent { diff --git a/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt b/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt index 8edd32c7..90a3208c 100644 --- a/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt +++ b/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt @@ -12,25 +12,8 @@ class HomeClipViewHolder( private val onClickEmptyClip: () -> Unit, ) : RecyclerView.ViewHolder(binding.root) { fun onBind(data: Category?, position: Int) { - if (position == 0) { - binding.ivHomeClip.setImageResource(org.sopt.mainfeature.R.drawable.ic_clip_all_24) - } - if (data == null) { - with(binding) { - clItemClip.isGone = true - clItemClipEmpty.isVisible = true - root.setOnClickListener { - onClickEmptyClip() - } - } - return - } - with(binding) { - tvItemClipTitle.text = data.categoryTitle - tvItemClipCount.text = data.toastNum.toString() + "개" - root.setOnClickListener { - onClickClip(data) - } - } + binding.tvLinkTitle.text = "sa" + binding.tvLinkUrl.text = "asd" + binding.tvLinkClipTitle.text = "asdsd" } } diff --git a/feature/home/src/main/res/layout/fragment_home.xml b/feature/home/src/main/res/layout/fragment_home.xml index c9c935c1..a93d3e8f 100644 --- a/feature/home/src/main/res/layout/fragment_home.xml +++ b/feature/home/src/main/res/layout/fragment_home.xml @@ -189,18 +189,26 @@ app:layout_constraintStart_toEndOf="@+id/tv_home_user_clip_name" app:layout_constraintTop_toTopOf="@id/tv_home_user_clip_name" /> + + + android:layout_marginBottom="8dp" + android:background="@drawable/shape_white_fill_12_rect" + android:paddingBottom="12dp"> - + android:id="@+id/iv_link_thumnail" + android:layout_width="74dp" + android:layout_height="74dp" + android:adjustViewBounds="true" + android:elevation="0dp" + android:scaleType="centerCrop" + android:src="@drawable/img_link_thumb" + app:layout_constraintDimensionRatio="1:1" /> + - - - + - - - - + app:layout_constraintTop_toTopOf="parent" + tools:text="세부 클립명" /> + + + + From be824c0439365aff214fe95cfcb9b0c85363cc89 Mon Sep 17 00:00:00 2001 From: leeseokchan00 <112953135+leeseokchan00@users.noreply.github.com> Date: Wed, 30 Oct 2024 06:47:58 +0900 Subject: [PATCH 2/7] [feat] #178 recent clip api --- .../org/sopt/model/home/RecentSavedLink.kt | 10 +++++++ .../org/sopt/remote/home/api/HomeService.kt | 5 ++++ .../datasource/RemoteHomeDataSourceImpl.kt | 4 +++ .../response/ResponseRecentSavedLinkDto.kt | 30 +++++++++++++++++++ .../home/datasource/RemoteHomeDataSource.kt | 2 ++ .../org/sopt/home/repository/HomeRepoImpl.kt | 4 +++ .../sopt/home/repository/HomeRepository.kt | 2 ++ .../sopt/home/usecase/GetRecentSavedLink.kt | 11 +++++++ .../main/java/org/sopt/home/HomeViewModel.kt | 2 ++ .../org/sopt/home/adapter/HomeClipAdapter.kt | 2 +- 10 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 core/model/src/main/java/org/sopt/model/home/RecentSavedLink.kt create mode 100644 data-remote/home/src/main/java/org/sopt/remote/home/response/ResponseRecentSavedLinkDto.kt create mode 100644 domain/home/src/main/java/org/sopt/home/usecase/GetRecentSavedLink.kt diff --git a/core/model/src/main/java/org/sopt/model/home/RecentSavedLink.kt b/core/model/src/main/java/org/sopt/model/home/RecentSavedLink.kt new file mode 100644 index 00000000..5e384464 --- /dev/null +++ b/core/model/src/main/java/org/sopt/model/home/RecentSavedLink.kt @@ -0,0 +1,10 @@ +package org.sopt.model.home + +data class RecentSavedLink( + val toastId: Long, + val toastTitle: String, + val linkUrl: String, + val isRead: Boolean, + val categoryTitle: String?, + val thumbnailUrl: String?, +) diff --git a/data-remote/home/src/main/java/org/sopt/remote/home/api/HomeService.kt b/data-remote/home/src/main/java/org/sopt/remote/home/api/HomeService.kt index 8c9fc520..518753e8 100644 --- a/data-remote/home/src/main/java/org/sopt/remote/home/api/HomeService.kt +++ b/data-remote/home/src/main/java/org/sopt/remote/home/api/HomeService.kt @@ -2,6 +2,7 @@ package org.sopt.remote.home.api import org.sopt.network.model.response.base.BaseResponse import org.sopt.remote.home.response.ResponseMainPageDto +import org.sopt.remote.home.response.ResponseRecentSavedLinkDto import org.sopt.remote.home.response.ResponseRecommendLinkDto import org.sopt.remote.home.response.ResponseWeekBestLinkDto import retrofit2.http.GET @@ -13,6 +14,7 @@ interface HomeService { const val SITES = "sites" const val TOAST = "toast" const val WEEK = "week" + const val RECENT_SAVED = "recent-saved" } @GET("/$USER/$MAIN") @@ -23,4 +25,7 @@ interface HomeService { @GET("/$TOAST/$WEEK") suspend fun getWeekBestLink(): BaseResponse> + + @GET("/$TOAST/$RECENT_SAVED") + suspend fun getRecentSavedLink(): BaseResponse> } diff --git a/data-remote/home/src/main/java/org/sopt/remote/home/datasource/RemoteHomeDataSourceImpl.kt b/data-remote/home/src/main/java/org/sopt/remote/home/datasource/RemoteHomeDataSourceImpl.kt index ebe14cf7..6169c216 100644 --- a/data-remote/home/src/main/java/org/sopt/remote/home/datasource/RemoteHomeDataSourceImpl.kt +++ b/data-remote/home/src/main/java/org/sopt/remote/home/datasource/RemoteHomeDataSourceImpl.kt @@ -2,6 +2,7 @@ package org.sopt.remote.home.datasource import org.sopt.home.datasource.RemoteHomeDataSource import org.sopt.model.home.MainPageData +import org.sopt.model.home.RecentSavedLink import org.sopt.model.home.RecommendLink import org.sopt.model.home.WeekBestLink import org.sopt.remote.home.api.HomeService @@ -19,4 +20,7 @@ class RemoteHomeDataSourceImpl @Inject constructor( override suspend fun getWeekBestLink(): List = homeService.getWeekBestLink().data!!.map { it.toCoreModel() } + + override suspend fun getRecentSavedLink(): List = + homeService.getRecentSavedLink().data!!.map { it.toCoreModel() } } diff --git a/data-remote/home/src/main/java/org/sopt/remote/home/response/ResponseRecentSavedLinkDto.kt b/data-remote/home/src/main/java/org/sopt/remote/home/response/ResponseRecentSavedLinkDto.kt new file mode 100644 index 00000000..5fbf1df7 --- /dev/null +++ b/data-remote/home/src/main/java/org/sopt/remote/home/response/ResponseRecentSavedLinkDto.kt @@ -0,0 +1,30 @@ +package org.sopt.remote.home.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import org.sopt.model.home.RecentSavedLink + +@Serializable +data class ResponseRecentSavedLinkDto( + @SerialName("toastId") + val toastId: Long, + @SerialName("toastTitle") + val toastTitle: String, + @SerialName("linkUrl") + val linkUrl: String, + @SerialName("isRead") + val isRead: Boolean, + @SerialName("categoryTitle") + val categoryTitle: String?, + @SerialName("thumbnailUrl") + val thumbnailUrl: String?, +) + +internal fun ResponseRecentSavedLinkDto.toCoreModel() = RecentSavedLink( + toastId = toastId, + toastTitle = toastTitle, + linkUrl = linkUrl, + isRead = isRead, + categoryTitle = categoryTitle, + thumbnailUrl = thumbnailUrl, +) diff --git a/data/home/src/main/java/org/sopt/home/datasource/RemoteHomeDataSource.kt b/data/home/src/main/java/org/sopt/home/datasource/RemoteHomeDataSource.kt index d4c22f58..06b841ef 100644 --- a/data/home/src/main/java/org/sopt/home/datasource/RemoteHomeDataSource.kt +++ b/data/home/src/main/java/org/sopt/home/datasource/RemoteHomeDataSource.kt @@ -1,6 +1,7 @@ package org.sopt.home.datasource import org.sopt.model.home.MainPageData +import org.sopt.model.home.RecentSavedLink import org.sopt.model.home.RecommendLink import org.sopt.model.home.WeekBestLink @@ -8,4 +9,5 @@ interface RemoteHomeDataSource { suspend fun getMainPageUserClip(): MainPageData suspend fun getRecommendSite(): List suspend fun getWeekBestLink(): List + suspend fun getRecentSavedLink(): List } diff --git a/data/home/src/main/java/org/sopt/home/repository/HomeRepoImpl.kt b/data/home/src/main/java/org/sopt/home/repository/HomeRepoImpl.kt index 75a241a7..b8794c3f 100644 --- a/data/home/src/main/java/org/sopt/home/repository/HomeRepoImpl.kt +++ b/data/home/src/main/java/org/sopt/home/repository/HomeRepoImpl.kt @@ -2,6 +2,7 @@ package org.sopt.home.repository import org.sopt.home.datasource.RemoteHomeDataSource import org.sopt.model.home.MainPageData +import org.sopt.model.home.RecentSavedLink import org.sopt.model.home.RecommendLink import org.sopt.model.home.WeekBestLink import javax.inject.Inject @@ -17,4 +18,7 @@ class HomeRepoImpl @Inject constructor( override suspend fun getWeekBestLink(): Result> = runCatching { remoteHomeDataSource.getWeekBestLink() } + + override suspend fun getRecentSavedLink(): Result> = + runCatching { remoteHomeDataSource.getRecentSavedLink() } } diff --git a/domain/home/src/main/java/org/sopt/home/repository/HomeRepository.kt b/domain/home/src/main/java/org/sopt/home/repository/HomeRepository.kt index a60a7f74..d6eda74b 100644 --- a/domain/home/src/main/java/org/sopt/home/repository/HomeRepository.kt +++ b/domain/home/src/main/java/org/sopt/home/repository/HomeRepository.kt @@ -1,6 +1,7 @@ package org.sopt.home.repository import org.sopt.model.home.MainPageData +import org.sopt.model.home.RecentSavedLink import org.sopt.model.home.RecommendLink import org.sopt.model.home.WeekBestLink @@ -8,4 +9,5 @@ interface HomeRepository { suspend fun getMainPageUserClip(): Result suspend fun getRecommendSite(): Result> suspend fun getWeekBestLink(): Result> + suspend fun getRecentSavedLink(): Result> } diff --git a/domain/home/src/main/java/org/sopt/home/usecase/GetRecentSavedLink.kt b/domain/home/src/main/java/org/sopt/home/usecase/GetRecentSavedLink.kt new file mode 100644 index 00000000..e0d33fde --- /dev/null +++ b/domain/home/src/main/java/org/sopt/home/usecase/GetRecentSavedLink.kt @@ -0,0 +1,11 @@ +package org.sopt.home.usecase + +import org.sopt.home.repository.HomeRepository +import org.sopt.model.home.RecentSavedLink +import javax.inject.Inject + +class GetRecentSavedLink @Inject constructor( + private val homeRepository: HomeRepository, +) { + suspend operator fun invoke(): Result> = homeRepository.getRecentSavedLink() +} diff --git a/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt b/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt index 22b73263..0f54345a 100644 --- a/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt +++ b/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt @@ -15,6 +15,7 @@ import org.orbitmvi.orbit.syntax.simple.reduce import org.orbitmvi.orbit.viewmodel.container import org.sopt.domain.category.category.usecase.PostAddCategoryTitleUseCase import org.sopt.home.usecase.GetMainPageUserClip +import org.sopt.home.usecase.GetRecentSavedLink import org.sopt.home.usecase.GetRecommendSite import org.sopt.home.usecase.GetWeekBestLink import org.sopt.model.category.Category @@ -26,6 +27,7 @@ class HomeViewModel @Inject constructor( private val getRecommendSite: GetRecommendSite, private val getWeekBestLink: GetWeekBestLink, private val postAddCategoryTitle: PostAddCategoryTitleUseCase, + private val getRecentSavedLink: GetRecentSavedLink, ) : ContainerHost, ViewModel() { override val container: Container = container(HomeState()) diff --git a/feature/home/src/main/java/org/sopt/home/adapter/HomeClipAdapter.kt b/feature/home/src/main/java/org/sopt/home/adapter/HomeClipAdapter.kt index 84b6fab9..961332ba 100644 --- a/feature/home/src/main/java/org/sopt/home/adapter/HomeClipAdapter.kt +++ b/feature/home/src/main/java/org/sopt/home/adapter/HomeClipAdapter.kt @@ -24,7 +24,7 @@ class HomeClipAdapter( ) } - override fun getItemCount() = currentList.size.coerceAtMost(4) + override fun getItemCount() = currentList.size.coerceAtMost(3) companion object { private val DiffUtil = ItemDiffCallback( From c8e8dcf2b1baa5e6f7babf0b1bbf0afc5788a3df Mon Sep 17 00:00:00 2001 From: leeseokchan00 <112953135+leeseokchan00@users.noreply.github.com> Date: Thu, 31 Oct 2024 03:17:03 +0900 Subject: [PATCH 3/7] [feat] #178 binding view --- .../main/java/org/sopt/home/HomeContract.kt | 4 +- .../main/java/org/sopt/home/HomeFragment.kt | 36 ++++------- .../main/java/org/sopt/home/HomeViewModel.kt | 18 +++++- .../org/sopt/home/adapter/HomeClipAdapter.kt | 7 ++- .../home/viewholder/HomeClipViewHolder.kt | 34 +++++++++-- .../src/main/res/layout/fragment_home.xml | 3 +- .../src/main/res/layout/item_home_clip.xml | 61 ++++++++++++++++++- 7 files changed, 127 insertions(+), 36 deletions(-) diff --git a/feature/home/src/main/java/org/sopt/home/HomeContract.kt b/feature/home/src/main/java/org/sopt/home/HomeContract.kt index 1ea351de..bb58466a 100644 --- a/feature/home/src/main/java/org/sopt/home/HomeContract.kt +++ b/feature/home/src/main/java/org/sopt/home/HomeContract.kt @@ -1,6 +1,7 @@ package org.sopt.home import org.sopt.model.category.Category +import org.sopt.model.home.RecentSavedLink import org.sopt.model.home.RecommendLink import org.sopt.model.home.WeekBestLink @@ -11,6 +12,7 @@ data class HomeState( val categoryList: List = emptyList(), val weekBestLink: List = emptyList(), val recommendLink: List = emptyList(), + val recentSavedLink: List = emptyList(), val url: String = "", val categoryId: Long? = 0, val categoryName: String? = "전체 클립", @@ -31,5 +33,5 @@ sealed interface HomeSideEffect { data object NavigateClipLink : HomeSideEffect data object NavigateAllClip : HomeSideEffect data object NavigateWebView : HomeSideEffect - data object ShowBottomSheet : HomeSideEffect + data object NavigateSaveLink : HomeSideEffect } diff --git a/feature/home/src/main/java/org/sopt/home/HomeFragment.kt b/feature/home/src/main/java/org/sopt/home/HomeFragment.kt index 15f44492..fa656351 100644 --- a/feature/home/src/main/java/org/sopt/home/HomeFragment.kt +++ b/feature/home/src/main/java/org/sopt/home/HomeFragment.kt @@ -5,8 +5,6 @@ import android.view.View import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import dagger.hilt.android.AndroidEntryPoint -import designsystem.components.bottomsheet.LinkMindBottomSheet -import designsystem.components.toast.linkMindSnackBar import org.orbitmvi.orbit.viewmodel.observe import org.sopt.common.util.delSpace import org.sopt.home.adapter.HomeClipAdapter @@ -51,7 +49,7 @@ class HomeFragment : BindingFragment({ FragmentHomeBinding. binding.tvHomeUserClipName.text = homeState.nickName binding.tvHomeToastLinkCount.text = "${homeState.readToastNum}개의 링크" binding.pbLinkmindHome.setProgressBarMain(homeState.calculateProgress()) - homeClipAdapter.submitList(homeState.categoryList) + homeClipAdapter.submitList(homeState.recentSavedLink) homeWeekLinkAdapter.submitList(homeState.weekBestLink) homeWeekRecommendLinkAdapter.submitList(homeState.recommendLink) } @@ -63,7 +61,8 @@ class HomeFragment : BindingFragment({ FragmentHomeBinding. is HomeSideEffect.NavigateClipLink -> navigateToDestination( "featureSaveLink://ClipLinkFragment/${viewModel.container.stateFlow.value.categoryId}/${viewModel.container.stateFlow.value.categoryName}", ) - is HomeSideEffect.ShowBottomSheet -> showHomeBottomSheet() + + is HomeSideEffect.NavigateSaveLink -> navigateToSavedClip() is HomeSideEffect.NavigateWebView -> { val encodedURL = URLEncoder.encode(viewModel.container.stateFlow.value.url, StandardCharsets.UTF_8.toString()) navigateToDestination( @@ -81,9 +80,11 @@ class HomeFragment : BindingFragment({ FragmentHomeBinding. viewModel.apply { getMainPageUserClip() getRecommendSite() + getRecentSavedClip() getWeekBestLink() } } + private fun navigateToSetting() { binding.ivHomeSetting.onThrottleClick { viewModel.navigateSetting() @@ -96,7 +97,7 @@ class HomeFragment : BindingFragment({ FragmentHomeBinding. } } - private fun navigateToAllClip(){ + private fun navigateToAllClip() { binding.ivRecentClip.onThrottleClick { viewModel.navigateAllClip() } @@ -108,13 +109,11 @@ class HomeFragment : BindingFragment({ FragmentHomeBinding. viewModel.navigateClipLink(it.categoryId, it.categoryTitle) }, onClickEmptyClip = { - viewModel.showBottomSheet() + viewModel.navigateSaveLink() }, ) binding.rvHomeClip.adapter = homeClipAdapter - val spacingClipInPixels = resources.getDimensionPixelSize(R.dimen.spacing_11) - binding.rvHomeClip.addItemDecoration(ItemDecoration(2, spacingClipInPixels)) - } + } private fun setWeekLinkAdapter() { homeWeekLinkAdapter = HomeWeekLinkAdapter( @@ -147,24 +146,13 @@ class HomeFragment : BindingFragment({ FragmentHomeBinding. findNavController().navigate(request, navOptions) } - private fun navigateToClip(){ + private fun navigateToClip() { val (request, navOptions) = DeepLinkUtil.getNavRequestNotPopUpAndOption("featureSaveLink://ClipLinkFragment/0/전체 클립") findNavController().navigate(request, navOptions) } - private fun showHomeBottomSheet() { - val linkMindBottomSheet = LinkMindBottomSheet(requireContext()) - linkMindBottomSheet.show() - linkMindBottomSheet.apply { - setBottomSheetHint(org.sopt.mainfeature.R.string.home_new_clip_info) - setTitle(org.sopt.mainfeature.R.string.home_add_clip) - setErroMsg(org.sopt.mainfeature.R.string.home_error_clip_info) - bottomSheetConfirmBtnClick { - if (showErrorMsg()) return@bottomSheetConfirmBtnClick - viewModel.saveCategoryTitle(it) - dismiss() - requireContext().linkMindSnackBar(binding.vSnack, "클립 생성 완료!", false) - } - } + private fun navigateToSavedClip(){ + val (request, navOptions) = DeepLinkUtil.getNavRequestNotPopUpAndOption("featureSaveLink://saveLinkFragment?clipboardLink=") + findNavController().navigate(request, navOptions) } } diff --git a/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt b/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt index 0f54345a..c8b2718b 100644 --- a/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt +++ b/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt @@ -68,6 +68,22 @@ class HomeViewModel @Inject constructor( } } + fun getRecentSavedClip() = intent { + getRecentSavedLink.invoke().onSuccess { + if(it.isEmpty()) { + reduce { + state.copy(recentSavedLink = listOf(null)) + } + } else { + reduce { + state.copy(recentSavedLink = (container.stateFlow.value.recentSavedLink + it).distinctBy { it?.toastId }) + } + } + }.onFailure { + Log.d("RecentSaved", "$it") + } + } + fun getRecommendSite() = intent { getRecommendSite.invoke().onSuccess { reduce { @@ -90,7 +106,7 @@ class HomeViewModel @Inject constructor( fun navigateSearch() = intent { postSideEffect(HomeSideEffect.NavigateSearch) } fun navigateSetting() = intent { postSideEffect(HomeSideEffect.NavigateSetting) } - fun showBottomSheet() = intent { postSideEffect(HomeSideEffect.ShowBottomSheet) } + fun navigateSaveLink() = intent { postSideEffect(HomeSideEffect.NavigateSaveLink) } fun navigateAllClip() = intent { postSideEffect(HomeSideEffect.NavigateAllClip) } @OptIn(OrbitExperimental::class) diff --git a/feature/home/src/main/java/org/sopt/home/adapter/HomeClipAdapter.kt b/feature/home/src/main/java/org/sopt/home/adapter/HomeClipAdapter.kt index 961332ba..7cea9972 100644 --- a/feature/home/src/main/java/org/sopt/home/adapter/HomeClipAdapter.kt +++ b/feature/home/src/main/java/org/sopt/home/adapter/HomeClipAdapter.kt @@ -6,12 +6,13 @@ import androidx.recyclerview.widget.ListAdapter import org.sopt.home.databinding.ItemHomeClipBinding import org.sopt.home.viewholder.HomeClipViewHolder import org.sopt.model.category.Category +import org.sopt.model.home.RecentSavedLink import org.sopt.ui.view.ItemDiffCallback class HomeClipAdapter( private val onClickClip: (Category) -> Unit, private val onClickEmptyClip: () -> Unit, -) : ListAdapter(DiffUtil) { +) : ListAdapter(DiffUtil) { override fun onBindViewHolder(holder: HomeClipViewHolder, position: Int) { holder.onBind(getItem(position), position) } @@ -27,8 +28,8 @@ class HomeClipAdapter( override fun getItemCount() = currentList.size.coerceAtMost(3) companion object { - private val DiffUtil = ItemDiffCallback( - onItemsTheSame = { old, new -> old.categoryId == new.categoryId }, + private val DiffUtil = ItemDiffCallback( + onItemsTheSame = { old, new -> old.toastId == new.toastId }, onContentsTheSame = { old, new -> old == new }, ) } diff --git a/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt b/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt index 90a3208c..8c9a189e 100644 --- a/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt +++ b/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt @@ -3,17 +3,43 @@ package org.sopt.home.viewholder import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView +import coil.load import org.sopt.home.databinding.ItemHomeClipBinding import org.sopt.model.category.Category +import org.sopt.model.home.RecentSavedLink class HomeClipViewHolder( private val binding: ItemHomeClipBinding, private val onClickClip: (Category) -> Unit, private val onClickEmptyClip: () -> Unit, ) : RecyclerView.ViewHolder(binding.root) { - fun onBind(data: Category?, position: Int) { - binding.tvLinkTitle.text = "sa" - binding.tvLinkUrl.text = "asd" - binding.tvLinkClipTitle.text = "asdsd" + fun onBind(data: RecentSavedLink?, position: Int) { + if (data==null) { + with(binding) { + clHomeItemClip.isGone = true + clHomeItemClipEmpty.isVisible = true + root.setOnClickListener { + onClickEmptyClip() + //TODO. onClick 수정, ui삐꾸난거 잡기 + } + } + return + } + with(binding) { + tvLinkTitle.text = data.toastTitle + tvLinkUrl.text = data.linkUrl + if (data.categoryTitle.isNullOrEmpty()) { + tvLinkClipTitle.isGone = true + } else { + tvLinkClipTitle.isVisible = true + tvLinkClipTitle.text = data.categoryTitle + } + ivLinkThumnail.load(data.thumbnailUrl) + if (data.isRead) { + tvItemClipLink.isVisible = true + } else { + tvItemClipLink.isGone = true + } + } } } diff --git a/feature/home/src/main/res/layout/fragment_home.xml b/feature/home/src/main/res/layout/fragment_home.xml index a93d3e8f..3958f0ef 100644 --- a/feature/home/src/main/res/layout/fragment_home.xml +++ b/feature/home/src/main/res/layout/fragment_home.xml @@ -204,9 +204,10 @@ android:layout_width="match_parent" android:layout_height="0dp" android:paddingHorizontal="20dp" - android:paddingTop="15dp" + android:paddingTop="14dp" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_home_user_clip_name" tools:itemCount="2" tools:listitem="@layout/item_home_clip" /> diff --git a/feature/home/src/main/res/layout/item_home_clip.xml b/feature/home/src/main/res/layout/item_home_clip.xml index fbb76b76..9245ec80 100644 --- a/feature/home/src/main/res/layout/item_home_clip.xml +++ b/feature/home/src/main/res/layout/item_home_clip.xml @@ -6,8 +6,13 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp" - android:background="@drawable/shape_white_fill_12_rect" - android:paddingBottom="12dp"> + android:background="@drawable/shape_white_fill_12_rect"> + + @@ -99,4 +106,54 @@ app:layout_constraintBottom_toBottomOf="@id/cv_link_thumnail" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/cv_link_thumnail" /> + + + + + + + + + + + From 19e9be920c63d16920c1bd8ce9e1b3181272c943 Mon Sep 17 00:00:00 2001 From: leeseokchan00 <112953135+leeseokchan00@users.noreply.github.com> Date: Thu, 31 Oct 2024 16:36:59 +0900 Subject: [PATCH 4/7] [feat] #178 item click event --- .../main/java/org/sopt/home/HomeFragment.kt | 20 ++++------ .../main/java/org/sopt/home/HomeViewModel.kt | 40 +------------------ .../org/sopt/home/adapter/HomeClipAdapter.kt | 3 +- .../home/viewholder/HomeClipViewHolder.kt | 10 +++-- 4 files changed, 16 insertions(+), 57 deletions(-) diff --git a/feature/home/src/main/java/org/sopt/home/HomeFragment.kt b/feature/home/src/main/java/org/sopt/home/HomeFragment.kt index fa656351..97380d02 100644 --- a/feature/home/src/main/java/org/sopt/home/HomeFragment.kt +++ b/feature/home/src/main/java/org/sopt/home/HomeFragment.kt @@ -61,15 +61,14 @@ class HomeFragment : BindingFragment({ FragmentHomeBinding. is HomeSideEffect.NavigateClipLink -> navigateToDestination( "featureSaveLink://ClipLinkFragment/${viewModel.container.stateFlow.value.categoryId}/${viewModel.container.stateFlow.value.categoryName}", ) - - is HomeSideEffect.NavigateSaveLink -> navigateToSavedClip() + is HomeSideEffect.NavigateSaveLink -> navigateToDestinationWithoutAnim("featureSaveLink://saveLinkFragment?clipboardLink=") is HomeSideEffect.NavigateWebView -> { val encodedURL = URLEncoder.encode(viewModel.container.stateFlow.value.url, StandardCharsets.UTF_8.toString()) navigateToDestination( "featureSaveLink://webViewFragment/${0}/${false}/${false}/$encodedURL", ) } - is HomeSideEffect.NavigateAllClip -> navigateToClip() + is HomeSideEffect.NavigateAllClip -> navigateToDestinationWithoutAnim("featureSaveLink://ClipLinkFragment/0/전체 클립") } } @@ -106,14 +105,14 @@ class HomeFragment : BindingFragment({ FragmentHomeBinding. private fun setClipAdapter() { homeClipAdapter = HomeClipAdapter( onClickClip = { - viewModel.navigateClipLink(it.categoryId, it.categoryTitle) + viewModel.navigateWebview(it.linkUrl) }, onClickEmptyClip = { viewModel.navigateSaveLink() }, ) binding.rvHomeClip.adapter = homeClipAdapter - } + } private fun setWeekLinkAdapter() { homeWeekLinkAdapter = HomeWeekLinkAdapter( @@ -146,13 +145,10 @@ class HomeFragment : BindingFragment({ FragmentHomeBinding. findNavController().navigate(request, navOptions) } - private fun navigateToClip() { - val (request, navOptions) = DeepLinkUtil.getNavRequestNotPopUpAndOption("featureSaveLink://ClipLinkFragment/0/전체 클립") - findNavController().navigate(request, navOptions) - } - - private fun navigateToSavedClip(){ - val (request, navOptions) = DeepLinkUtil.getNavRequestNotPopUpAndOption("featureSaveLink://saveLinkFragment?clipboardLink=") + private fun navigateToDestinationWithoutAnim(destination: String) { + val (request, navOptions) = DeepLinkUtil.getNavRequestNotPopUpAndOption( + destination.delSpace(), + ) findNavController().navigate(request, navOptions) } } diff --git a/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt b/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt index c8b2718b..c83cfa80 100644 --- a/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt +++ b/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt @@ -2,9 +2,7 @@ package org.sopt.home import android.util.Log import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch import org.orbitmvi.orbit.Container import org.orbitmvi.orbit.ContainerHost import org.orbitmvi.orbit.annotation.OrbitExperimental @@ -13,12 +11,10 @@ import org.orbitmvi.orbit.syntax.simple.intent import org.orbitmvi.orbit.syntax.simple.postSideEffect import org.orbitmvi.orbit.syntax.simple.reduce import org.orbitmvi.orbit.viewmodel.container -import org.sopt.domain.category.category.usecase.PostAddCategoryTitleUseCase import org.sopt.home.usecase.GetMainPageUserClip import org.sopt.home.usecase.GetRecentSavedLink import org.sopt.home.usecase.GetRecommendSite import org.sopt.home.usecase.GetWeekBestLink -import org.sopt.model.category.Category import javax.inject.Inject @HiltViewModel @@ -26,41 +22,18 @@ class HomeViewModel @Inject constructor( private val getMainPageUserClip: GetMainPageUserClip, private val getRecommendSite: GetRecommendSite, private val getWeekBestLink: GetWeekBestLink, - private val postAddCategoryTitle: PostAddCategoryTitleUseCase, private val getRecentSavedLink: GetRecentSavedLink, ) : ContainerHost, ViewModel() { override val container: Container = container(HomeState()) - fun saveCategoryTitle(categoryTitle: String) = viewModelScope.launch { - postAddCategoryTitle( - PostAddCategoryTitleUseCase.Param( - categoryTitle = categoryTitle, - ), - ).onSuccess { - getMainPageUserClip() - }.onFailure { Log.d("saveCategoryTitleFail", "$it") } - } - fun getMainPageUserClip() = intent { getMainPageUserClip.invoke().onSuccess { reduce { - val tempCategoryList = listOf( - Category( - 0, - "전체 카테고리", - it.allToastNum.toLong(), - ), - ) + it.mainCategoryDto - val categoryList = if (tempCategoryList.size < 4) tempCategoryList + null else tempCategoryList - val finalCategoryList = categoryList.distinctBy { it?.categoryId } state.copy( nickName = it.nickName, allToastNum = it.allToastNum, readToastNum = it.readToastNum, - categoryList = ( - finalCategoryList - ), ) } }.onFailure { @@ -70,7 +43,7 @@ class HomeViewModel @Inject constructor( fun getRecentSavedClip() = intent { getRecentSavedLink.invoke().onSuccess { - if(it.isEmpty()) { + if (it.isEmpty()) { reduce { state.copy(recentSavedLink = listOf(null)) } @@ -109,17 +82,6 @@ class HomeViewModel @Inject constructor( fun navigateSaveLink() = intent { postSideEffect(HomeSideEffect.NavigateSaveLink) } fun navigateAllClip() = intent { postSideEffect(HomeSideEffect.NavigateAllClip) } - @OptIn(OrbitExperimental::class) - fun navigateClipLink(categoryId: Long?, categoryName: String?) = blockingIntent { - reduce { - state.copy( - categoryId = categoryId, - categoryName = categoryName, - ) - } - postSideEffect(HomeSideEffect.NavigateClipLink) - } - @OptIn(OrbitExperimental::class) fun navigateWebview(url: String) = blockingIntent { reduce { state.copy(url = url) } diff --git a/feature/home/src/main/java/org/sopt/home/adapter/HomeClipAdapter.kt b/feature/home/src/main/java/org/sopt/home/adapter/HomeClipAdapter.kt index 7cea9972..f5e76860 100644 --- a/feature/home/src/main/java/org/sopt/home/adapter/HomeClipAdapter.kt +++ b/feature/home/src/main/java/org/sopt/home/adapter/HomeClipAdapter.kt @@ -5,12 +5,11 @@ import android.view.ViewGroup import androidx.recyclerview.widget.ListAdapter import org.sopt.home.databinding.ItemHomeClipBinding import org.sopt.home.viewholder.HomeClipViewHolder -import org.sopt.model.category.Category import org.sopt.model.home.RecentSavedLink import org.sopt.ui.view.ItemDiffCallback class HomeClipAdapter( - private val onClickClip: (Category) -> Unit, + private val onClickClip: (RecentSavedLink) -> Unit, private val onClickEmptyClip: () -> Unit, ) : ListAdapter(DiffUtil) { override fun onBindViewHolder(holder: HomeClipViewHolder, position: Int) { diff --git a/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt b/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt index 8c9a189e..0f2d443a 100644 --- a/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt +++ b/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt @@ -5,22 +5,21 @@ import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView import coil.load import org.sopt.home.databinding.ItemHomeClipBinding -import org.sopt.model.category.Category import org.sopt.model.home.RecentSavedLink +import org.sopt.ui.view.onThrottleClick class HomeClipViewHolder( private val binding: ItemHomeClipBinding, - private val onClickClip: (Category) -> Unit, + private val onClickClip: (RecentSavedLink) -> Unit, private val onClickEmptyClip: () -> Unit, ) : RecyclerView.ViewHolder(binding.root) { fun onBind(data: RecentSavedLink?, position: Int) { - if (data==null) { + if (data == null) { with(binding) { clHomeItemClip.isGone = true clHomeItemClipEmpty.isVisible = true root.setOnClickListener { onClickEmptyClip() - //TODO. onClick 수정, ui삐꾸난거 잡기 } } return @@ -40,6 +39,9 @@ class HomeClipViewHolder( } else { tvItemClipLink.isGone = true } + root.onThrottleClick { + onClickClip.invoke(data) + } } } } From 223f56ade5f5caea79fd97db1b1ffd6259c3d812 Mon Sep 17 00:00:00 2001 From: leeseokchan00 <112953135+leeseokchan00@users.noreply.github.com> Date: Thu, 31 Oct 2024 16:56:37 +0900 Subject: [PATCH 5/7] [refactor] #178 text value --- core/designsystem/src/main/res/values/strings.xml | 2 ++ feature/home/src/main/res/layout/item_home_clip.xml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/core/designsystem/src/main/res/values/strings.xml b/core/designsystem/src/main/res/values/strings.xml index 64cb89ff..dcd80f25 100644 --- a/core/designsystem/src/main/res/values/strings.xml +++ b/core/designsystem/src/main/res/values/strings.xml @@ -155,6 +155,8 @@ 님이 최근 저장한 링크 이주의 링크 이주의 추천 사이트 + 첫번째 링크를 저장해보세요 + 클립의 이름은 최대 15자까지 입력 가능해요 diff --git a/feature/home/src/main/res/layout/item_home_clip.xml b/feature/home/src/main/res/layout/item_home_clip.xml index 9245ec80..f1ced3bd 100644 --- a/feature/home/src/main/res/layout/item_home_clip.xml +++ b/feature/home/src/main/res/layout/item_home_clip.xml @@ -147,7 +147,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="1dp" - android:text="@string/clip_add_clip" + android:text="@string/home_item_link_empty" android:textAppearance="@style/Typography.suit.bold_14" android:textColor="@color/neutrals200" app:layout_constraintBottom_toBottomOf="parent" From 0d207a2f8cf85d4fa3ab4e72b9ff12bf62212c93 Mon Sep 17 00:00:00 2001 From: leeseokchan00 <112953135+leeseokchan00@users.noreply.github.com> Date: Wed, 6 Nov 2024 18:25:57 +0900 Subject: [PATCH 6/7] [chore] #178 ktlint --- feature/home/src/main/java/org/sopt/home/HomeContract.kt | 2 +- feature/home/src/main/java/org/sopt/home/HomeViewModel.kt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/feature/home/src/main/java/org/sopt/home/HomeContract.kt b/feature/home/src/main/java/org/sopt/home/HomeContract.kt index 80338c99..e73040e5 100644 --- a/feature/home/src/main/java/org/sopt/home/HomeContract.kt +++ b/feature/home/src/main/java/org/sopt/home/HomeContract.kt @@ -2,8 +2,8 @@ package org.sopt.home import org.sopt.home.model.UpdatePriority import org.sopt.model.category.Category -import org.sopt.model.home.RecentSavedLink import org.sopt.model.home.PopupInfo +import org.sopt.model.home.RecentSavedLink import org.sopt.model.home.RecommendLink import org.sopt.model.home.WeekBestLink diff --git a/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt b/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt index 2c5bf520..60b9d2f7 100644 --- a/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt +++ b/feature/home/src/main/java/org/sopt/home/HomeViewModel.kt @@ -22,12 +22,11 @@ import org.sopt.datastore.datastore.SecurityDataStore import org.sopt.domain.category.category.usecase.PostAddCategoryTitleUseCase import org.sopt.home.model.UpdatePriority import org.sopt.home.usecase.GetMainPageUserClip -import org.sopt.home.usecase.GetRecentSavedLink import org.sopt.home.usecase.GetPopupInfo +import org.sopt.home.usecase.GetRecentSavedLink import org.sopt.home.usecase.GetRecommendSite import org.sopt.home.usecase.GetWeekBestLink import org.sopt.home.usecase.PatchPopupInvisible -import org.sopt.model.category.Category import java.text.SimpleDateFormat import java.util.Calendar import java.util.Locale From daa0b794927b7749c68db4a026ca4b062fec7f64 Mon Sep 17 00:00:00 2001 From: leeseokchan00 <112953135+leeseokchan00@users.noreply.github.com> Date: Wed, 6 Nov 2024 19:00:01 +0900 Subject: [PATCH 7/7] [refactor] #178 refactor --- .../home/viewholder/HomeClipViewHolder.kt | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt b/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt index 0f2d443a..93395f85 100644 --- a/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt +++ b/feature/home/src/main/java/org/sopt/home/viewholder/HomeClipViewHolder.kt @@ -1,5 +1,6 @@ package org.sopt.home.viewholder +import android.view.View import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView @@ -27,21 +28,17 @@ class HomeClipViewHolder( with(binding) { tvLinkTitle.text = data.toastTitle tvLinkUrl.text = data.linkUrl - if (data.categoryTitle.isNullOrEmpty()) { - tvLinkClipTitle.isGone = true - } else { - tvLinkClipTitle.isVisible = true - tvLinkClipTitle.text = data.categoryTitle - } + binding.tvLinkTitle.setVisible(!data.categoryTitle.isNullOrEmpty()) + tvLinkClipTitle.text = data.categoryTitle ivLinkThumnail.load(data.thumbnailUrl) - if (data.isRead) { - tvItemClipLink.isVisible = true - } else { - tvItemClipLink.isGone = true - } + tvItemClipLink.setVisible(data.isRead) root.onThrottleClick { onClickClip.invoke(data) } } } + + private fun View.setVisible(value: Boolean) { + visibility = if (value) View.VISIBLE else View.GONE + } }