Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions core/designsystem/src/main/res/drawable/ic_arrow_black_svg.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="8dp"
android:height="14dp"
android:viewportWidth="8"
android:viewportHeight="14">
<path
android:pathData="M0.999,12.833L6.832,7L0.999,1.166"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#191919"
android:strokeLineCap="round"/>
</vector>
4 changes: 3 additions & 1 deletion core/designsystem/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,11 @@
<string name="home_unforget_read">์žŠ์ง€ ์•Š๊ณ  ์ฝ์—ˆ์–ด์š”!</string>
<string name="home_toast_progress_link">nn</string>
<string name="home_all_toast_ex_num">/nn</string>
<string name="home_user_clip">๋‹˜์˜ ํด๋ฆฝ</string>
<string name="home_user_clip">๋‹˜์ด ์ตœ๊ทผ ์ €์žฅํ•œ ๋งํฌ</string>
<string name="home_this_week_link">์ด์ฃผ์˜ ๋งํฌ</string>
<string name="home_this_week_recommend">์ด์ฃผ์˜ ์ถ”์ฒœ ์‚ฌ์ดํŠธ</string>
<string name="home_item_link_empty">์ฒซ๋ฒˆ์งธ ๋งํฌ๋ฅผ ์ €์žฅํ•ด๋ณด์„ธ์š”</string>

<string name="home_survey_title">1๋ถ„ ์„ค๋ฌธ์กฐ์‚ฌ ์ฐธ์—ฌํ•˜๊ณ \n์Šคํƒ€๋ฒ…์Šค ๊ธฐํ”„ํ‹ฐ์ฝ˜ ๋ฐ›๊ธฐ</string>
<string name="home_survey_subtitle">ํ† ์Šคํ„ฐ ์‚ฌ์šฉ ํ”ผ๋“œ๋ฐฑ์„ ๋‚จ๊ฒจ์ฃผ์‹œ๋ฉด\n์ถ”์ฒจ์„ ํ†ตํ•ด ๊ธฐํ”„ํ‹ฐ์ฝ˜์„ ๋“œ๋ ค์š”!</string>
<string name="home_survey_button">์ฐธ์—ฌํ•˜๊ธฐ</string>
Expand Down
10 changes: 10 additions & 0 deletions core/model/src/main/java/org/sopt/model/home/RecentSavedLink.kt
Original file line number Diff line number Diff line change
@@ -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?,
)
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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")
Expand All @@ -23,4 +25,7 @@ interface HomeService {

@GET("/$TOAST/$WEEK")
suspend fun getWeekBestLink(): BaseResponse<List<ResponseWeekBestLinkDto>>

@GET("/$TOAST/$RECENT_SAVED")
suspend fun getRecentSavedLink(): BaseResponse<List<ResponseRecentSavedLinkDto>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -19,4 +20,7 @@ class RemoteHomeDataSourceImpl @Inject constructor(

override suspend fun getWeekBestLink(): List<WeekBestLink> =
homeService.getWeekBestLink().data!!.map { it.toCoreModel() }

override suspend fun getRecentSavedLink(): List<RecentSavedLink> =
homeService.getRecentSavedLink().data!!.map { it.toCoreModel() }
}
Original file line number Diff line number Diff line change
@@ -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,
)
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
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

interface RemoteHomeDataSource {
suspend fun getMainPageUserClip(): MainPageData
suspend fun getRecommendSite(): List<RecommendLink>
suspend fun getWeekBestLink(): List<WeekBestLink>
suspend fun getRecentSavedLink(): List<RecentSavedLink>
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -17,4 +18,7 @@ class HomeRepoImpl @Inject constructor(

override suspend fun getWeekBestLink(): Result<List<WeekBestLink>> =
runCatching { remoteHomeDataSource.getWeekBestLink() }

override suspend fun getRecentSavedLink(): Result<List<RecentSavedLink>> =
runCatching { remoteHomeDataSource.getRecentSavedLink() }
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
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

interface HomeRepository {
suspend fun getMainPageUserClip(): Result<MainPageData>
suspend fun getRecommendSite(): Result<List<RecommendLink>>
suspend fun getWeekBestLink(): Result<List<WeekBestLink>>
suspend fun getRecentSavedLink(): Result<List<RecentSavedLink>>
}
Original file line number Diff line number Diff line change
@@ -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<List<RecentSavedLink>> = homeRepository.getRecentSavedLink()
}
5 changes: 4 additions & 1 deletion feature/home/src/main/java/org/sopt/home/HomeContract.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.sopt.home
import org.sopt.home.model.UpdatePriority
import org.sopt.model.category.Category
import org.sopt.model.home.PopupInfo
import org.sopt.model.home.RecentSavedLink
import org.sopt.model.home.RecommendLink
import org.sopt.model.home.WeekBestLink

Expand All @@ -13,6 +14,7 @@ data class HomeState(
val categoryList: List<Category?> = emptyList(),
val weekBestLink: List<WeekBestLink> = emptyList(),
val recommendLink: List<RecommendLink> = emptyList(),
val recentSavedLink: List<RecentSavedLink?> = emptyList(),
val url: String = "",
val categoryId: Long? = 0,
val categoryName: String? = "์ „์ฒด ํด๋ฆฝ",
Expand All @@ -33,8 +35,9 @@ 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
data object ShowPopupInfo : HomeSideEffect
data object ShowUpdateDialog : HomeSideEffect
data object NavigateSaveLink : HomeSideEffect
}
42 changes: 18 additions & 24 deletions feature/home/src/main/java/org/sopt/home/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -36,6 +34,7 @@ class HomeFragment : BindingFragment<FragmentHomeBinding>({ FragmentHomeBinding.
collectState()
navigateToSetting()
navigateToSearch()
navigateToAllClip()
}

private fun initView() {
Expand All @@ -53,7 +52,7 @@ class HomeFragment : BindingFragment<FragmentHomeBinding>({ 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)
}
Expand All @@ -65,15 +64,14 @@ class HomeFragment : BindingFragment<FragmentHomeBinding>({ FragmentHomeBinding.
is HomeSideEffect.NavigateClipLink -> navigateToDestination(
"featureSaveLink://ClipLinkFragment/${viewModel.container.stateFlow.value.categoryId}/${viewModel.container.stateFlow.value.categoryName}",
)

is HomeSideEffect.ShowBottomSheet -> showHomeBottomSheet()
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 -> navigateToDestinationWithoutAnim("featureSaveLink://ClipLinkFragment/0/์ „์ฒด ํด๋ฆฝ")
is HomeSideEffect.ShowPopupInfo -> showPopupInfo(viewModel.container.stateFlow.value.popupList)
is HomeSideEffect.ShowUpdateDialog -> showUpdateDialog(viewModel.container.stateFlow.value.marketUpdate)
}
Expand All @@ -86,6 +84,7 @@ class HomeFragment : BindingFragment<FragmentHomeBinding>({ FragmentHomeBinding.
viewModel.apply {
getMainPageUserClip()
getRecommendSite()
getRecentSavedClip()
getWeekBestLink()
getPopupListInfo()
checkMarketUpdateState()
Expand All @@ -104,18 +103,22 @@ class HomeFragment : BindingFragment<FragmentHomeBinding>({ FragmentHomeBinding.
}
}

private fun navigateToAllClip() {
binding.ivRecentClip.onThrottleClick {
viewModel.navigateAllClip()
}
}

private fun setClipAdapter() {
homeClipAdapter = HomeClipAdapter(
onClickClip = {
viewModel.navigateClipLink(it.categoryId, it.categoryTitle)
viewModel.navigateWebview(it.linkUrl)
},
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() {
Expand Down Expand Up @@ -149,20 +152,11 @@ class HomeFragment : BindingFragment<FragmentHomeBinding>({ FragmentHomeBinding.
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 navigateToDestinationWithoutAnim(destination: String) {
val (request, navOptions) = DeepLinkUtil.getNavRequestNotPopUpAndOption(
destination.delSpace(),
)
findNavController().navigate(request, navOptions)
}

private fun showPopupInfo(popupList: List<PopupInfo>) {
Expand Down
55 changes: 20 additions & 35 deletions feature/home/src/main/java/org/sopt/home/HomeViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ 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.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
Expand All @@ -38,6 +38,7 @@ class HomeViewModel @Inject constructor(
private val getMainPageUserClip: GetMainPageUserClip,
private val getRecommendSite: GetRecommendSite,
private val getWeekBestLink: GetWeekBestLink,
private val getRecentSavedLink: GetRecentSavedLink,
private val postAddCategoryTitle: PostAddCategoryTitleUseCase,
private val patchPopupInvisible: PatchPopupInvisible,
private val getPopupInfo: GetPopupInfo,
Expand All @@ -46,42 +47,36 @@ class HomeViewModel @Inject constructor(
override val container: Container<HomeState, HomeSideEffect> =
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 {
Log.d("MainUser", "$it")
}
}

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 {
Expand Down Expand Up @@ -151,18 +146,8 @@ class HomeViewModel @Inject constructor(

fun navigateSearch() = intent { postSideEffect(HomeSideEffect.NavigateSearch) }
fun navigateSetting() = intent { postSideEffect(HomeSideEffect.NavigateSetting) }
fun showBottomSheet() = intent { postSideEffect(HomeSideEffect.ShowBottomSheet) }

@OptIn(OrbitExperimental::class)
fun navigateClipLink(categoryId: Long?, categoryName: String?) = blockingIntent {
reduce {
state.copy(
categoryId = categoryId,
categoryName = categoryName,
)
}
postSideEffect(HomeSideEffect.NavigateClipLink)
}
fun navigateSaveLink() = intent { postSideEffect(HomeSideEffect.NavigateSaveLink) }
fun navigateAllClip() = intent { postSideEffect(HomeSideEffect.NavigateAllClip) }

@OptIn(OrbitExperimental::class)
fun navigateWebview(url: String) = blockingIntent {
Expand Down
Loading
Loading