diff --git a/data/src/main/kotlin/com/mashup/dorabangs/data/datasource/remote/api/AIClassificationRemoteDataSource.kt b/data/src/main/kotlin/com/mashup/dorabangs/data/datasource/remote/api/AIClassificationRemoteDataSource.kt index 69897896..5c6fe200 100644 --- a/data/src/main/kotlin/com/mashup/dorabangs/data/datasource/remote/api/AIClassificationRemoteDataSource.kt +++ b/data/src/main/kotlin/com/mashup/dorabangs/data/datasource/remote/api/AIClassificationRemoteDataSource.kt @@ -2,7 +2,6 @@ package com.mashup.dorabangs.data.datasource.remote.api import com.mashup.dorabangs.data.model.classification.AIClassificationAIPostListResponseModel import com.mashup.dorabangs.domain.model.AIClassificationFolders -import com.mashup.dorabangs.domain.model.AIClassificationPosts interface AIClassificationRemoteDataSource { @@ -23,7 +22,7 @@ interface AIClassificationRemoteDataSource { page: Int? = null, limit: Int? = null, order: String? = null, - ): AIClassificationPosts + ): AIClassificationAIPostListResponseModel suspend fun deletePostFromAIClassification( postId: String, diff --git a/data/src/main/kotlin/com/mashup/dorabangs/data/datasource/remote/impl/AIClassificationRemoteDataSourceImpl.kt b/data/src/main/kotlin/com/mashup/dorabangs/data/datasource/remote/impl/AIClassificationRemoteDataSourceImpl.kt index 614180c3..ffbd7d06 100644 --- a/data/src/main/kotlin/com/mashup/dorabangs/data/datasource/remote/impl/AIClassificationRemoteDataSourceImpl.kt +++ b/data/src/main/kotlin/com/mashup/dorabangs/data/datasource/remote/impl/AIClassificationRemoteDataSourceImpl.kt @@ -6,7 +6,6 @@ import com.mashup.dorabangs.data.model.classification.AIClassificationAIPostList import com.mashup.dorabangs.data.model.toDomain import com.mashup.dorabangs.data.network.service.AIClassificationService import com.mashup.dorabangs.domain.model.AIClassificationFolders -import com.mashup.dorabangs.domain.model.AIClassificationPosts import javax.inject.Inject class AIClassificationRemoteDataSourceImpl @Inject constructor( @@ -38,13 +37,13 @@ class AIClassificationRemoteDataSourceImpl @Inject constructor( page: Int?, limit: Int?, order: String?, - ): AIClassificationPosts = + ): AIClassificationAIPostListResponseModel = service.getAIClassificationPostsByFolder( folderId = folderId, page = page, limit = limit, order = order, - ).toDomain() + ) override suspend fun deletePostFromAIClassification(postId: String) = service.deletePostFromAIClassification( diff --git a/data/src/main/kotlin/com/mashup/dorabangs/data/network/service/AIClassificationService.kt b/data/src/main/kotlin/com/mashup/dorabangs/data/network/service/AIClassificationService.kt index 19541233..8e0e85f3 100644 --- a/data/src/main/kotlin/com/mashup/dorabangs/data/network/service/AIClassificationService.kt +++ b/data/src/main/kotlin/com/mashup/dorabangs/data/network/service/AIClassificationService.kt @@ -1,7 +1,6 @@ package com.mashup.dorabangs.data.network.service import com.mashup.dorabangs.data.model.AIClassificationFoldersResponseModel -import com.mashup.dorabangs.data.model.AIClassificationPostsResponseModel import com.mashup.dorabangs.data.model.AiClassificationMoveSinglePostRequestModel import com.mashup.dorabangs.data.model.classification.AIClassificationAIPostListResponseModel import retrofit2.http.Body @@ -40,7 +39,7 @@ interface AIClassificationService { @Query("page") page: Int? = null, @Query("limit") limit: Int? = null, @Query("order") order: String? = null, - ): AIClassificationPostsResponseModel + ): AIClassificationAIPostListResponseModel @DELETE("classification/posts/{postId}") suspend fun deletePostFromAIClassification( diff --git a/data/src/main/kotlin/com/mashup/dorabangs/data/repository/AIClassificationRepositoryImpl.kt b/data/src/main/kotlin/com/mashup/dorabangs/data/repository/AIClassificationRepositoryImpl.kt index 5e905144..c330171d 100644 --- a/data/src/main/kotlin/com/mashup/dorabangs/data/repository/AIClassificationRepositoryImpl.kt +++ b/data/src/main/kotlin/com/mashup/dorabangs/data/repository/AIClassificationRepositoryImpl.kt @@ -5,7 +5,6 @@ import com.mashup.dorabangs.data.datasource.remote.api.AIClassificationRemoteDat import com.mashup.dorabangs.data.model.classification.toPagingDomain import com.mashup.dorabangs.data.utils.doraPager import com.mashup.dorabangs.domain.model.AIClassificationFolders -import com.mashup.dorabangs.domain.model.AIClassificationPosts import com.mashup.dorabangs.domain.model.DoraSampleResponse import com.mashup.dorabangs.domain.model.classification.AIClassificationFeedPost import com.mashup.dorabangs.domain.repository.AIClassificationRepository @@ -44,16 +43,19 @@ class AIClassificationRepositoryImpl @Inject constructor( override suspend fun getAIClassificationPostsByFolder( folderId: String, - page: Int?, limit: Int?, order: String?, - ): AIClassificationPosts = - remoteDataSource.getAIClassificationPostsByFolder( - folderId = folderId, - page = page, - limit = limit, - order = order, - ) + ): Flow> = + doraPager( + apiExecutor = { page -> + remoteDataSource.getAIClassificationPostsByFolder( + folderId = folderId, + page = page, + limit = limit, + order = order, + ).toPagingDomain() + }, + ).flow override suspend fun deletePostFromAIClassification(postId: String): DoraSampleResponse { return kotlin.runCatching { diff --git a/domain/src/main/kotlin/com/mashup/dorabangs/domain/repository/AIClassificationRepository.kt b/domain/src/main/kotlin/com/mashup/dorabangs/domain/repository/AIClassificationRepository.kt index f78dd75b..7260d7ec 100644 --- a/domain/src/main/kotlin/com/mashup/dorabangs/domain/repository/AIClassificationRepository.kt +++ b/domain/src/main/kotlin/com/mashup/dorabangs/domain/repository/AIClassificationRepository.kt @@ -2,7 +2,6 @@ package com.mashup.dorabangs.domain.repository import androidx.paging.PagingData import com.mashup.dorabangs.domain.model.AIClassificationFolders -import com.mashup.dorabangs.domain.model.AIClassificationPosts import com.mashup.dorabangs.domain.model.DoraSampleResponse import com.mashup.dorabangs.domain.model.classification.AIClassificationFeedPost import kotlinx.coroutines.flow.Flow @@ -22,10 +21,9 @@ interface AIClassificationRepository { suspend fun getAIClassificationPostsByFolder( folderId: String, - page: Int? = null, limit: Int? = null, order: String? = null, - ): AIClassificationPosts + ): Flow> suspend fun deletePostFromAIClassification( postId: String, diff --git a/domain/src/main/kotlin/com/mashup/dorabangs/domain/usecase/aiclassification/GetAIClassificationPostsByFolderUseCase.kt b/domain/src/main/kotlin/com/mashup/dorabangs/domain/usecase/aiclassification/GetAIClassificationPostsByFolderUseCase.kt index 95f6fd9e..ee9753b3 100644 --- a/domain/src/main/kotlin/com/mashup/dorabangs/domain/usecase/aiclassification/GetAIClassificationPostsByFolderUseCase.kt +++ b/domain/src/main/kotlin/com/mashup/dorabangs/domain/usecase/aiclassification/GetAIClassificationPostsByFolderUseCase.kt @@ -10,13 +10,11 @@ class GetAIClassificationPostsByFolderUseCase @Inject constructor( suspend operator fun invoke( folderId: String, - page: Int? = null, limit: Int? = null, order: Sort? = null, ) = aiClassificationRepository.getAIClassificationPostsByFolder( folderId = folderId, - page = page, limit = limit, order = order?.query, ) diff --git a/feature/classification/src/main/java/com/mashup/feature/classification/ClassificationListScreen.kt b/feature/classification/src/main/java/com/mashup/feature/classification/ClassificationListScreen.kt index 16821ac1..0b43f187 100644 --- a/feature/classification/src/main/java/com/mashup/feature/classification/ClassificationListScreen.kt +++ b/feature/classification/src/main/java/com/mashup/feature/classification/ClassificationListScreen.kt @@ -55,26 +55,22 @@ fun ClassificationListScreen( pagingList[idx]?.let { item -> when (item) { is FeedUiModel.DoraChipUiModel -> { - if (state.selectedFolder == item.title || state.selectedFolder == "전체") { - ClassificationFolderMove( - selectedFolder = item.title, - onClickAllItemMoveButton = { onClickAllItemMoveButton(item.folderId) }, - count = item.postCount, - ) - } + ClassificationFolderMove( + selectedFolder = item.title, + onClickAllItemMoveButton = { onClickAllItemMoveButton(item.folderId) }, + count = item.postCount, + ) } is FeedUiModel.FeedCardUiModel -> { - if (state.selectedFolder == item.category || state.selectedFolder == "전체") { - ClassificationCardItem( - idx = idx, - lastIndex = pagingList.itemCount - 1, - cardItem = item, - onClickDeleteButton = onClickDeleteButton, - onClickMoveButton = onClickMoveButton, - onClickCardItem = onClickCardItem, - ) - } + ClassificationCardItem( + idx = idx, + lastIndex = pagingList.itemCount - 1, + cardItem = item, + onClickDeleteButton = onClickDeleteButton, + onClickMoveButton = onClickMoveButton, + onClickCardItem = onClickCardItem, + ) } } } diff --git a/feature/classification/src/main/java/com/mashup/feature/classification/ClassificationState.kt b/feature/classification/src/main/java/com/mashup/feature/classification/ClassificationState.kt index 90827be0..82b1bfc8 100644 --- a/feature/classification/src/main/java/com/mashup/feature/classification/ClassificationState.kt +++ b/feature/classification/src/main/java/com/mashup/feature/classification/ClassificationState.kt @@ -4,7 +4,6 @@ import com.mashup.dorabangs.core.designsystem.component.chips.FeedUiModel data class ClassificationState( val chipState: ChipState = ChipState(), - val selectedFolder: String = "전체", val isLoading: Boolean = false, ) diff --git a/feature/classification/src/main/java/com/mashup/feature/classification/ClassificationViewModel.kt b/feature/classification/src/main/java/com/mashup/feature/classification/ClassificationViewModel.kt index 64143288..6a56358e 100644 --- a/feature/classification/src/main/java/com/mashup/feature/classification/ClassificationViewModel.kt +++ b/feature/classification/src/main/java/com/mashup/feature/classification/ClassificationViewModel.kt @@ -11,9 +11,11 @@ import com.mashup.dorabangs.core.coroutine.doraLaunch import com.mashup.dorabangs.core.designsystem.component.chips.FeedUiModel import com.mashup.dorabangs.domain.model.AIClassificationFolders import com.mashup.dorabangs.domain.model.PostInfo +import com.mashup.dorabangs.domain.model.Sort import com.mashup.dorabangs.domain.model.classification.AIClassificationFeedPost import com.mashup.dorabangs.domain.usecase.aiclassification.DeletePostFromAIClassificationUseCase import com.mashup.dorabangs.domain.usecase.aiclassification.GetAIClassificationFolderListUseCase +import com.mashup.dorabangs.domain.usecase.aiclassification.GetAIClassificationPostsByFolderUseCase import com.mashup.dorabangs.domain.usecase.aiclassification.GetAIClassificationPostsUseCase import com.mashup.dorabangs.domain.usecase.aiclassification.MoveAllPostsToRecommendedFolderUseCase import com.mashup.dorabangs.domain.usecase.aiclassification.MoveSinglePostToRecommendedFolderUseCase @@ -33,6 +35,7 @@ import javax.inject.Inject class ClassificationViewModel @Inject constructor( private val getAIClassificationFolderListUseCase: GetAIClassificationFolderListUseCase, private val getAIClassificationPostsUseCase: GetAIClassificationPostsUseCase, + private val getAIClassificationFolderListByIdUseCase: GetAIClassificationPostsByFolderUseCase, private val deletePostUseCase: DeletePostFromAIClassificationUseCase, private val moveSinglePostUseCase: MoveSinglePostToRecommendedFolderUseCase, private val moveAllPostUseCase: MoveAllPostsToRecommendedFolderUseCase, @@ -109,12 +112,51 @@ class ClassificationViewModel @Inject constructor( } } - fun changeCategory(idx: Int) = intent { - reduce { - state.copy( - chipState = state.chipState.copy(currentIndex = idx), - selectedFolder = state.chipState.chipList.getOrNull(idx)?.title ?: "전체", - ) + fun changeCategory(idx: Int) = viewModelScope.doraLaunch { + intent { + val selectedFolderItem = state.chipState.chipList.getOrNull(idx) + val selectedFolderId = selectedFolderItem?.id.orEmpty() + val selectedFolderName = selectedFolderItem?.title.orEmpty() + + getAIClassificationFolderListByIdUseCase.invoke( + folderId = selectedFolderId, + limit = LIMIT, + order = Sort.DESC, + ).map { pagedData -> + // chip create + pagedData.map { + val category = + state.chipState.chipList.firstOrNull { chip -> chip.id == it.folderId }?.title.orEmpty() + it.toUiModel(category) + } + }.map { + // add seperator + it.insertSeparators { before, after -> + after?.let { + if (before?.category != after.category) { + FeedUiModel.DoraChipUiModel( + id = selectedFolderId, + mergedTitle = "", + title = selectedFolderName, + postCount = selectedFolderItem?.postCount ?: 0, + folderId = after.folderId, + icon = null, + ) + } else { + null + } + } + } + }.cachedIn(viewModelScope) + .let { + _paging.value = it.firstOrNull() ?: PagingData.empty() + } + + reduce { + state.copy( + chipState = state.chipState.copy(currentIndex = idx), + ) + } } } @@ -124,9 +166,9 @@ class ClassificationViewModel @Inject constructor( state.copy(isLoading = true) } } - val allMove = moveAllPostUseCase.invoke(suggestionFolderId = folderId) + val allMoveItem = moveAllPostUseCase.invoke(suggestionFolderId = folderId) - if (allMove.isSuccess) { + if (allMoveItem.isSuccess) { getInitialData() } }.invokeOnCompletion { @@ -136,19 +178,31 @@ class ClassificationViewModel @Inject constructor( } fun moveSelectedItem(cardItem: FeedUiModel.FeedCardUiModel) = viewModelScope.doraLaunch { - val move = moveSinglePostUseCase.invoke( - postId = cardItem.postId, - suggestionFolderId = cardItem.folderId, - ) + intent { + reduce { + state.copy( + isLoading = true, + ) + } + val moveItem = moveSinglePostUseCase.invoke( + postId = cardItem.postId, + suggestionFolderId = cardItem.folderId, + ) + + if (moveItem.isSuccess) { + val (chips, chipList) = updateChipList() + val findCategory = chips.list.find { it.folderId == cardItem.folderId } - if (move.isSuccess) { - val (chips, chipList) = updateChipList() - updateListScreenWithSingleItem(cardItem) + if (findCategory != null) { + updateListScreenWithSingleItem(cardItem) + updateSeparator(chipList) + } else { + getInitialData() + } - intent { reduce { state.copy( - chipState = ChipState( + chipState = state.chipState.copy( totalCount = chips.totalCounts, chipList = chipList, ), @@ -156,18 +210,38 @@ class ClassificationViewModel @Inject constructor( } } } + }.invokeOnCompletion { + intent { + reduce { + state.copy( + isLoading = false, + ) + } + } } fun deleteSelectedItem(cardItem: FeedUiModel.FeedCardUiModel) = viewModelScope.doraLaunch { - val delete = deletePostUseCase.invoke(cardItem.postId) - if (delete.isSuccess) { - val (chips, chipList) = updateChipList() - updateListScreenWithSingleItem(cardItem) + intent { + reduce { + state.copy( + isLoading = true, + ) + } + val deleteItem = deletePostUseCase.invoke(cardItem.postId) + if (deleteItem.isSuccess) { + val (chips, chipList) = updateChipList() + val findCategory = chips.list.find { it.folderId == cardItem.folderId } + + if (findCategory != null) { + updateListScreenWithSingleItem(cardItem) + updateSeparator(chipList) + } else { + getInitialData() + } - intent { reduce { state.copy( - chipState = ChipState( + chipState = state.chipState.copy( totalCount = chips.totalCounts, chipList = chipList, ), @@ -175,6 +249,25 @@ class ClassificationViewModel @Inject constructor( } } } + }.invokeOnCompletion { + intent { + reduce { + state.copy( + isLoading = false, + ) + } + } + } + + private fun updateSeparator(chipList: List) { + _paging.value = _paging.value.map { + if (it is FeedUiModel.DoraChipUiModel) { + val updateItem = chipList.find { chip -> chip.id == it.folderId } + it.copy(postCount = updateItem?.postCount ?: it.postCount) + } else { + it + } + } } private suspend fun updateListScreenWithSingleItem(cardItem: FeedUiModel.FeedCardUiModel) {