diff --git a/core/data/src/main/java/com/youthtalk/repository/CommunityRepositoryImpl.kt b/core/data/src/main/java/com/youthtalk/repository/CommunityRepositoryImpl.kt index 1188a910..4ab0573d 100644 --- a/core/data/src/main/java/com/youthtalk/repository/CommunityRepositoryImpl.kt +++ b/core/data/src/main/java/com/youthtalk/repository/CommunityRepositoryImpl.kt @@ -15,23 +15,21 @@ import com.youthtalk.data.CommunityService import com.youthtalk.datasource.post.MyPageRemoteMediator import com.youthtalk.datasource.post.PostRemoteMediator import com.youthtalk.datasource.room.YouthDatabase -import com.youthtalk.dto.MemberId import com.youthtalk.mapper.toData import com.youthtalk.mapper.toDomain import com.youthtalk.model.Image import com.youthtalk.model.post.CreatePost import com.youthtalk.model.post.ModifyPost import com.youthtalk.model.post.Post -import com.youthtalk.model.post.PostDetail import com.youthtalk.model.post.PostSubject import com.youthtalk.model.post.PostType import com.youthtalk.model.typeenum.Category -import com.youthtalk.utils.ErrorUtils.throwableError +import com.youthtalk.utils.ErrorUtils.createResult import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.withContext import timber.log.Timber class CommunityRepositoryImpl @Inject constructor( @@ -39,7 +37,7 @@ class CommunityRepositoryImpl @Inject constructor( private val youthDatabase: YouthDatabase, private val context: Context ) : CommunityRepository { - override fun getPopularPosts(category: Category, postSubject: PostSubject): Flow> = flow { + override suspend fun getPopularPosts(category: Category, postSubject: PostSubject): Result> = createResult { val categories = if (category == Category.ALL) { Category.entries.filter { it != Category.ALL }.map { it.name }.toList() } else { @@ -47,26 +45,14 @@ class CommunityRepositoryImpl @Inject constructor( category.name ) } - runCatching { - when (postSubject) { - PostSubject.REVIEW -> communityService.getReviewPosts(categories = categories, page = 0, size = 10) - PostSubject.POST -> communityService.getPosts(page = 0, size = 10) - } - } - .onSuccess { data -> - Timber.e("CommunityRepositoryImpl getPopularPosts Success $data") - data.data?.let { postResponse -> - emit(postResponse.popularPosts.map { it.toDomain() }) - } ?: throw NoDataException() - } - .onFailure { error -> - Timber.e("CommunityRepositoryImpl getPopularPosts error : $error") - throwableError(error) - } + when (postSubject) { + PostSubject.REVIEW -> communityService.getReviewPosts(categories = categories, page = 0, size = 10) + PostSubject.POST -> communityService.getPosts(page = 0, size = 10) + }.data?.popularPosts?.map { it.toDomain() } ?: throw NoDataException() } @OptIn(ExperimentalPagingApi::class) - override fun getPosts(category: Category, postType: PostType, postSubject: PostSubject): Flow>> = flow { + override fun getPosts(category: Category, postType: PostType, postSubject: PostSubject): Flow> { val categories = if (category == Category.ALL) { Category.entries.filter { it != Category.ALL }.map { it.name }.toList() } else { @@ -74,127 +60,88 @@ class CommunityRepositoryImpl @Inject constructor( category.name ) } - emit( - Pager( - config = PagingConfig( - pageSize = 10, - enablePlaceholders = true - ), - remoteMediator = PostRemoteMediator( - communityService = communityService, - categories = categories, - postType = postType, - postSubject = postSubject, - youthDatabase = youthDatabase - ) - ) { - youthDatabase.postDao().getPagingSource(postType = postType) - }.flow - ) + return Pager( + config = PagingConfig( + pageSize = 10, + enablePlaceholders = true + ), + remoteMediator = PostRemoteMediator( + communityService = communityService, + categories = categories, + postType = postType, + postSubject = postSubject, + youthDatabase = youthDatabase + ) + ) { + youthDatabase.postDao().getPagingSource(postType = postType) + }.flow } - override fun getListImage(): Flow> = flow { - val contentResolver = context.contentResolver - val projection = arrayOf( - Images.Media._ID, - Images.Media.DISPLAY_NAME, - Images.Media.SIZE, - Images.Media.MIME_TYPE - ) - - val collectionUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL) - } else { - Images.Media.EXTERNAL_CONTENT_URI - } - - val images = mutableListOf() - - contentResolver.query( - collectionUri, - projection, - null, - null, - "${Images.Media.DATE_ADDED} DESC" - )?.use { cursor -> - val idColumn = cursor.getColumnIndexOrThrow(Images.Media._ID) - val displayNameColumn = cursor.getColumnIndexOrThrow(Images.Media.DISPLAY_NAME) - val sizeColumn = cursor.getColumnIndexOrThrow(Images.Media.SIZE) - val mimeTypeColumn = cursor.getColumnIndexOrThrow(Images.Media.MIME_TYPE) - - while (cursor.moveToNext()) { - val uri = ContentUris.withAppendedId(collectionUri, cursor.getLong(idColumn)) - val name = cursor.getString(displayNameColumn) - val size = cursor.getLong(sizeColumn) - val mimeType = cursor.getString(mimeTypeColumn) + override suspend fun getListImage(): Result> = runCatching { + withContext(Dispatchers.IO) { + val contentResolver = context.contentResolver + val projection = arrayOf( + Images.Media._ID, + Images.Media.DISPLAY_NAME, + Images.Media.SIZE, + Images.Media.MIME_TYPE + ) - val image = Image(uri.toString(), name, size, mimeType) - images.add(image) + val collectionUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL) + } else { + Images.Media.EXTERNAL_CONTENT_URI + } + + val images = mutableListOf() + + contentResolver.query( + collectionUri, + projection, + null, + null, + "${Images.Media.DATE_ADDED} DESC" + )?.use { cursor -> + val idColumn = cursor.getColumnIndexOrThrow(Images.Media._ID) + val displayNameColumn = cursor.getColumnIndexOrThrow(Images.Media.DISPLAY_NAME) + val sizeColumn = cursor.getColumnIndexOrThrow(Images.Media.SIZE) + val mimeTypeColumn = cursor.getColumnIndexOrThrow(Images.Media.MIME_TYPE) + + while (cursor.moveToNext()) { + val uri = ContentUris.withAppendedId(collectionUri, cursor.getLong(idColumn)) + val name = cursor.getString(displayNameColumn) + val size = cursor.getLong(sizeColumn) + val mimeType = cursor.getString(mimeTypeColumn) + + val image = Image(uri.toString(), name, size, mimeType) + images.add(image) + } } + images } + } - emit(images) - }.flowOn(Dispatchers.IO) - - override fun postCreatePost(createPost: CreatePost): Flow = flow { - runCatching { - communityService.postCreate(createPost.toData().toRequestBody()) - } - .onSuccess { response -> - response.data?.let { post -> - emit(post.postId) - } - } - .onFailure { - Timber.e("postCreatePost error $it") - throwableError(it) - } + override suspend fun postCreatePost(createPost: CreatePost): Result = createResult { + communityService.postCreate(createPost.toData().toRequestBody()).data?.postId ?: throw NoDataException() } - override fun getPostDetail(postId: Long) = flow { - runCatching { - communityService.getPostDetail(postId) - } - .onSuccess { response -> - response.data?.let { post -> - emit(post.toData()) - } - } - .onFailure { - Timber.e("postCreatePost getPostDetail $it") - throwableError(it) - } + override suspend fun getPostDetail(postId: Long) = createResult { + communityService.getPostDetail(postId).data?.toData() ?: throw NoDataException() } - override fun deletePost(postId: Long): Flow = flow { - runCatching { - communityService.deletePost(postId) - } - .onSuccess { - youthDatabase.postDao().deletePost(postId) - emit(postId) - } - .onFailure { - Timber.e("postCreatePost deletePost $it") - throwableError(it) - } + override suspend fun deletePost(postId: Long): Result = createResult { + communityService.deletePost(postId) + youthDatabase.postDao().deletePost(postId) + postId } - override fun postPostScrap(postId: Long, scrap: Boolean): Flow = flow { - runCatching { - communityService.postPostScrap(postId) - } - .onSuccess { - youthDatabase.postDao().updatePostScrap(postId, !scrap) - emit(postId) - } - .onFailure { - Timber.e("postCreatePost postPostScrap $it") - throwableError(it) - } + override suspend fun postPostScrap(postId: Long, scrap: Boolean): Result = createResult { + communityService.postPostScrap(postId) + youthDatabase.postDao().updatePostScrap(postId, !scrap) + postId } - override fun syncPostScrap(reviews: List, frees: List): Flow, List>> = flow { + override suspend fun syncPostScrap(reviews: List, frees: List): Result, List>> = createResult { val syncReviews = reviews .map { post -> val syncPost = youthDatabase.postDao().getPost(post.postId)?.copy(postType = post.postType) @@ -204,66 +151,44 @@ class CommunityRepositoryImpl @Inject constructor( val syncFrees = frees .map { post -> youthDatabase.postDao().getPost(post.postId)?.copy(postType = post.postType) ?: post } - emit(Pair(syncReviews, syncFrees)) + Pair(syncReviews, syncFrees) } @OptIn(ExperimentalPagingApi::class) - override fun getSettingPosts(isScrapType: Boolean): Flow>> = flow { - emit( - Pager( - config = PagingConfig( - pageSize = 10, - enablePlaceholders = true - ), - remoteMediator = MyPageRemoteMediator( - communityService = communityService, - postType = PostType.MY_PAGE, - youthDatabase = youthDatabase, - isScrap = isScrapType - ) - ) { - if (isScrapType) { - youthDatabase.postDao().getScrapPagingSource(postType = PostType.MY_PAGE) - } else { - youthDatabase.postDao().getPagingSource(postType = PostType.MY_PAGE) - } - }.flow - ) - } - - override fun getSettingPostCount(isScrapType: Boolean): Flow = flow { - runCatching { + override fun getSettingPosts(isScrapType: Boolean): Flow> { + return Pager( + config = PagingConfig( + pageSize = 10, + enablePlaceholders = true + ), + remoteMediator = MyPageRemoteMediator( + communityService = communityService, + postType = PostType.MY_PAGE, + youthDatabase = youthDatabase, + isScrap = isScrapType + ) + ) { if (isScrapType) { - communityService.getScrapPosts(0, 1) + youthDatabase.postDao().getScrapPagingSource(postType = PostType.MY_PAGE) } else { - communityService.getMyPosts(0, 1) - } - } - .onSuccess { response -> - response.data?.let { - emit(it.total) - } - } - .onFailure { - Timber.e("CommunityRepositoryImpl getSettingPostCount $it") - throwableError(it) + youthDatabase.postDao().getPagingSource(postType = PostType.MY_PAGE) } + }.flow + } + + override suspend fun getSettingPostCount(isScrapType: Boolean): Result = createResult { + if (isScrapType) { + communityService.getScrapPosts(0, 1) + } else { + communityService.getMyPosts(0, 1) + }.data?.total ?: throw NoDataException() } - override fun postModifyPost(postId: Long, modifyPost: ModifyPost): Flow = flow { + override suspend fun postModifyPost(postId: Long, modifyPost: ModifyPost): Result = createResult { val requestBody = modifyPost.toData().toRequestBody() - runCatching { - communityService.postModifyPost(postId, requestBody) - } - .onSuccess { response -> - response.data?.let { postDetail -> - youthDatabase.postDao().updateModifyPost(postId, postDetail.title, postDetail.contentList[0].content.split("\n").first()) - emit(postDetail.postId) - } - } - .onFailure { - Timber.e("CommunityRepositoryImpl postModifyPost error $it") - throwableError(it) - } + + val postDetail = communityService.postModifyPost(postId, requestBody).data ?: throw NoDataException() + youthDatabase.postDao().updateModifyPost(postId, postDetail.title, postDetail.contentList[0].content.split("\n").first()) + postDetail.postId } } diff --git a/core/data/src/test/java/com/youthtalk/repository/CommunityRepositoryTest.kt b/core/data/src/test/java/com/youthtalk/repository/CommunityRepositoryTest.kt new file mode 100644 index 00000000..d5744bde --- /dev/null +++ b/core/data/src/test/java/com/youthtalk/repository/CommunityRepositoryTest.kt @@ -0,0 +1,84 @@ +package com.youthtalk.repository + +import android.content.Context +import com.core.dataapi.repository.CommunityRepository +import com.youthtalk.data.CommunityService +import com.youthtalk.datasource.room.YouthDatabase +import com.youthtalk.dto.CommonResponse +import com.youthtalk.dto.PostResponse +import com.youthtalk.model.post.Post +import com.youthtalk.model.post.PostSubject +import com.youthtalk.model.typeenum.Category +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@RunWith(MockitoJUnitRunner::class) +class CommunityRepositoryTest { + + private lateinit var sut: CommunityRepository + + @Mock + private lateinit var communityService: CommunityService + + @Mock + private lateinit var youthDatabase: YouthDatabase + + @Mock + private lateinit var context: Context + + @Before + fun setUp() { + sut = CommunityRepositoryImpl(communityService, youthDatabase, context) + } + + @Test + fun given_whenGetPopularPost_thenReturnsPosts() { + runTest { + // given + val page = 0 + val size = 10 + whenever(communityService.getPosts(page, size)).thenReturn(CommonResponse(200, "요청에 성공하였습니다", "S01", PostResponse(listOf(), listOf()))) + + // when + val result = sut.getPopularPosts(Category.JOB, PostSubject.POST).getOrThrow() + + // then + assertEquals(emptyList(), result) + verify(communityService).getPosts(page, size) + } + } + + @Test + fun given_whenGetPopularReview_thenReturnsReviews() { + runTest { + // given + val page = 0 + val size = 10 + whenever(communityService.getReviewPosts(page, size, listOf(Category.JOB.name))).thenReturn( + CommonResponse( + 200, + "요청에 성공하였습니다", + "S01", + PostResponse( + listOf(), + listOf() + ) + ) + ) + + // when + val result = sut.getPopularPosts(Category.JOB, PostSubject.REVIEW).getOrThrow() + + // then + assertEquals(emptyList(), result) + verify(communityService).getReviewPosts(page, size, listOf(Category.JOB.name)) + } + } +} diff --git a/core/dataApi/src/main/java/com/core/dataapi/repository/CommunityRepository.kt b/core/dataApi/src/main/java/com/core/dataapi/repository/CommunityRepository.kt index ba0a28a3..a12010ca 100644 --- a/core/dataApi/src/main/java/com/core/dataapi/repository/CommunityRepository.kt +++ b/core/dataApi/src/main/java/com/core/dataapi/repository/CommunityRepository.kt @@ -12,15 +12,15 @@ import com.youthtalk.model.typeenum.Category import kotlinx.coroutines.flow.Flow interface CommunityRepository { - fun getPopularPosts(category: Category, postSubject: PostSubject): Flow> - fun getPosts(category: Category, postType: PostType, postSubject: PostSubject): Flow>> - fun getListImage(): Flow> - fun postCreatePost(createPost: CreatePost): Flow - fun getPostDetail(postId: Long): Flow - fun deletePost(postId: Long): Flow - fun postPostScrap(postId: Long, scrap: Boolean): Flow - fun syncPostScrap(reviews: List, frees: List): Flow, List>> - fun getSettingPosts(isScrapType: Boolean): Flow>> - fun getSettingPostCount(isScrapType: Boolean): Flow - fun postModifyPost(postId: Long, modifyPost: ModifyPost): Flow + suspend fun getPopularPosts(category: Category, postSubject: PostSubject): Result> + fun getPosts(category: Category, postType: PostType, postSubject: PostSubject): Flow> + suspend fun getListImage(): Result> + suspend fun postCreatePost(createPost: CreatePost): Result + suspend fun getPostDetail(postId: Long): Result + suspend fun deletePost(postId: Long): Result + suspend fun postPostScrap(postId: Long, scrap: Boolean): Result + suspend fun syncPostScrap(reviews: List, frees: List): Result, List>> + fun getSettingPosts(isScrapType: Boolean): Flow> + suspend fun getSettingPostCount(isScrapType: Boolean): Result + suspend fun postModifyPost(postId: Long, modifyPost: ModifyPost): Result } diff --git a/core/domain/src/main/java/com/core/domain/usercase/GetImageListUseCase.kt b/core/domain/src/main/java/com/core/domain/usercase/GetImageListUseCase.kt index c13d4397..6c67293a 100644 --- a/core/domain/src/main/java/com/core/domain/usercase/GetImageListUseCase.kt +++ b/core/domain/src/main/java/com/core/domain/usercase/GetImageListUseCase.kt @@ -6,5 +6,5 @@ import javax.inject.Inject class GetImageListUseCase @Inject constructor( private val communityRepository: CommunityRepository ) { - operator fun invoke() = communityRepository.getListImage() + suspend operator fun invoke() = communityRepository.getListImage() } diff --git a/core/domain/src/main/java/com/core/domain/usercase/post/DeletePostUseCase.kt b/core/domain/src/main/java/com/core/domain/usercase/post/DeletePostUseCase.kt index b518ed0b..fba0b665 100644 --- a/core/domain/src/main/java/com/core/domain/usercase/post/DeletePostUseCase.kt +++ b/core/domain/src/main/java/com/core/domain/usercase/post/DeletePostUseCase.kt @@ -6,5 +6,5 @@ import javax.inject.Inject class DeletePostUseCase @Inject constructor( private val communityRepository: CommunityRepository ) { - operator fun invoke(postId: Long) = communityRepository.deletePost(postId) + suspend operator fun invoke(postId: Long) = communityRepository.deletePost(postId) } diff --git a/core/domain/src/main/java/com/core/domain/usercase/post/GetPopularPostsUseCase.kt b/core/domain/src/main/java/com/core/domain/usercase/post/GetPopularPostsUseCase.kt index b9780547..7583b321 100644 --- a/core/domain/src/main/java/com/core/domain/usercase/post/GetPopularPostsUseCase.kt +++ b/core/domain/src/main/java/com/core/domain/usercase/post/GetPopularPostsUseCase.kt @@ -8,5 +8,5 @@ import javax.inject.Inject class GetPopularPostsUseCase @Inject constructor( private val communityRepository: CommunityRepository ) { - operator fun invoke(category: Category, postSubject: PostSubject) = communityRepository.getPopularPosts(category, postSubject) + suspend operator fun invoke(category: Category, postSubject: PostSubject) = communityRepository.getPopularPosts(category, postSubject) } diff --git a/core/domain/src/main/java/com/core/domain/usercase/post/GetPostDetailUseCase.kt b/core/domain/src/main/java/com/core/domain/usercase/post/GetPostDetailUseCase.kt index 3f7ad5f5..b1e44194 100644 --- a/core/domain/src/main/java/com/core/domain/usercase/post/GetPostDetailUseCase.kt +++ b/core/domain/src/main/java/com/core/domain/usercase/post/GetPostDetailUseCase.kt @@ -6,5 +6,5 @@ import javax.inject.Inject class GetPostDetailUseCase @Inject constructor( private val communityRepository: CommunityRepository ) { - operator fun invoke(postId: Long) = communityRepository.getPostDetail(postId) + suspend operator fun invoke(postId: Long) = communityRepository.getPostDetail(postId) } diff --git a/core/domain/src/main/java/com/core/domain/usercase/post/GetSettingPostCountUseCase.kt b/core/domain/src/main/java/com/core/domain/usercase/post/GetSettingPostCountUseCase.kt index ad9ed345..faf1b952 100644 --- a/core/domain/src/main/java/com/core/domain/usercase/post/GetSettingPostCountUseCase.kt +++ b/core/domain/src/main/java/com/core/domain/usercase/post/GetSettingPostCountUseCase.kt @@ -6,5 +6,5 @@ import javax.inject.Inject class GetSettingPostCountUseCase @Inject constructor( private val communityRepository: CommunityRepository ) { - operator fun invoke(isScrap: Boolean) = communityRepository.getSettingPostCount(isScrap) + suspend operator fun invoke(isScrap: Boolean) = communityRepository.getSettingPostCount(isScrap) } diff --git a/core/domain/src/main/java/com/core/domain/usercase/post/PostCreatePostUseCase.kt b/core/domain/src/main/java/com/core/domain/usercase/post/PostCreatePostUseCase.kt index fe88681d..2423212b 100644 --- a/core/domain/src/main/java/com/core/domain/usercase/post/PostCreatePostUseCase.kt +++ b/core/domain/src/main/java/com/core/domain/usercase/post/PostCreatePostUseCase.kt @@ -7,5 +7,5 @@ import javax.inject.Inject class PostCreatePostUseCase @Inject constructor( private val communityRepository: CommunityRepository ) { - operator fun invoke(createPost: CreatePost) = communityRepository.postCreatePost(createPost) + suspend operator fun invoke(createPost: CreatePost) = communityRepository.postCreatePost(createPost) } diff --git a/core/domain/src/main/java/com/core/domain/usercase/post/PostModifyPostUseCase.kt b/core/domain/src/main/java/com/core/domain/usercase/post/PostModifyPostUseCase.kt index 20ed58a5..d95b4891 100644 --- a/core/domain/src/main/java/com/core/domain/usercase/post/PostModifyPostUseCase.kt +++ b/core/domain/src/main/java/com/core/domain/usercase/post/PostModifyPostUseCase.kt @@ -7,5 +7,5 @@ import javax.inject.Inject class PostModifyPostUseCase @Inject constructor( private val communityRepository: CommunityRepository ) { - operator fun invoke(postId: Long, modifyPost: ModifyPost) = communityRepository.postModifyPost(postId, modifyPost) + suspend operator fun invoke(postId: Long, modifyPost: ModifyPost) = communityRepository.postModifyPost(postId, modifyPost) } diff --git a/core/domain/src/main/java/com/core/domain/usercase/post/PostPostScrapUseCase.kt b/core/domain/src/main/java/com/core/domain/usercase/post/PostPostScrapUseCase.kt index ad7fff33..7c54b817 100644 --- a/core/domain/src/main/java/com/core/domain/usercase/post/PostPostScrapUseCase.kt +++ b/core/domain/src/main/java/com/core/domain/usercase/post/PostPostScrapUseCase.kt @@ -6,5 +6,5 @@ import javax.inject.Inject class PostPostScrapUseCase @Inject constructor( private val communityRepository: CommunityRepository ) { - operator fun invoke(postId: Long, scrap: Boolean) = communityRepository.postPostScrap(postId, scrap) + suspend operator fun invoke(postId: Long, scrap: Boolean) = communityRepository.postPostScrap(postId, scrap) } diff --git a/core/domain/src/main/java/com/core/domain/usercase/post/SyncPopularPostUseCase.kt b/core/domain/src/main/java/com/core/domain/usercase/post/SyncPopularPostUseCase.kt index 49224d84..8473cbaf 100644 --- a/core/domain/src/main/java/com/core/domain/usercase/post/SyncPopularPostUseCase.kt +++ b/core/domain/src/main/java/com/core/domain/usercase/post/SyncPopularPostUseCase.kt @@ -7,5 +7,5 @@ import javax.inject.Inject class SyncPopularPostUseCase @Inject constructor( private val communityRepository: CommunityRepository ) { - operator fun invoke(reviews: List, frees: List) = communityRepository.syncPostScrap(reviews, frees) + suspend operator fun invoke(reviews: List, frees: List) = communityRepository.syncPostScrap(reviews, frees) } diff --git a/feature/community/src/main/java/com/core/community/viewmodel/CommunityDetailViewModel.kt b/feature/community/src/main/java/com/core/community/viewmodel/CommunityDetailViewModel.kt index 6a0853e7..9844dc18 100644 --- a/feature/community/src/main/java/com/core/community/viewmodel/CommunityDetailViewModel.kt +++ b/feature/community/src/main/java/com/core/community/viewmodel/CommunityDetailViewModel.kt @@ -25,7 +25,6 @@ import java.time.LocalDateTime import javax.inject.Inject import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import timber.log.Timber @@ -97,10 +96,7 @@ class CommunityDetailViewModel @Inject constructor( private fun postPostScrap(postId: Long, scrap: Boolean) { viewModelScope.launch { postPostScrapUseCase(postId, scrap) - .catch { - Timber.e("CommunityDetailViewModel postPostScrap error $it") - } - .collectLatest { + .onSuccess { setState { copy( postDetail = state.value.postDetail.copy(scrap = !scrap) @@ -113,10 +109,7 @@ class CommunityDetailViewModel @Inject constructor( private fun deletePost(postId: Long) { viewModelScope.launch { deletePostUseCase(postId) - .catch { - Timber.e("CommunityDetailViewModel deletePost error $it") - } - .collectLatest { + .onSuccess { setEffect { CommunityDetailUiEffect.ShowSnackBarDeletePost } } } @@ -228,30 +221,19 @@ class CommunityDetailViewModel @Inject constructor( private fun initData(postId: Long) { viewModelScope.launch { val commentInfo = getPostDetailCommentsUseCase(postId) + val postDetail = getPostDetailUseCase(postId) - if (commentInfo.isFailure) { - Timber.e("commentInfoError ${commentInfo.exceptionOrNull()?.message}") - return@launch - } - - combine( - getUserUseCase(), - getPostDetailUseCase(postId) - ) { user, postDetail -> - CommunityDetailUiState( - user = user, - postDetail = postDetail, - comments = commentInfo.getOrThrow(), - detailType = CommunityDetailType.MAIN, - initLoading = false - ) - } + getUserUseCase() .catch { - Timber.e("CommunityDetailViewModel initData error $it") setEffect { CommunityDetailUiEffect.InitError("신고한 게시글은 조회할 수 없습니다.") } - } - .collectLatest { uiState -> - setState { uiState } + }.collect { user -> + CommunityDetailUiState( + user = user, + postDetail = postDetail.getOrThrow(), + comments = commentInfo.getOrThrow(), + detailType = CommunityDetailType.MAIN, + initLoading = false + ) } } } diff --git a/feature/community/src/main/java/com/core/community/viewmodel/CommunityViewModel.kt b/feature/community/src/main/java/com/core/community/viewmodel/CommunityViewModel.kt index d6228304..41352ed6 100644 --- a/feature/community/src/main/java/com/core/community/viewmodel/CommunityViewModel.kt +++ b/feature/community/src/main/java/com/core/community/viewmodel/CommunityViewModel.kt @@ -10,14 +10,14 @@ import com.core.domain.usercase.post.GetPopularPostsUseCase import com.core.domain.usercase.post.GetPostsUseCase import com.core.domain.usercase.post.PostPostScrapUseCase import com.core.domain.usercase.post.SyncPopularPostUseCase +import com.core.exception.BadRequestException import com.youthtalk.model.post.PostSubject import com.youthtalk.model.post.PostType import com.youthtalk.model.typeenum.Category import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject +import kotlinx.coroutines.async import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch import timber.log.Timber @@ -47,10 +47,7 @@ class CommunityViewModel @Inject constructor( private fun postPostScrap(postId: Long, scrap: Boolean) { viewModelScope.launch { postPostScrapUseCase(postId, scrap) - .catch { - Timber.e("CommunityViewModel postPostScrap error $it") - } - .collectLatest { + .onSuccess { setState { copy( popularFrees = popularFrees.map { post -> @@ -82,15 +79,11 @@ class CommunityViewModel @Inject constructor( private fun syncPopularPost() { viewModelScope.launch { syncPopularPostUseCase(state.value.popularReviews, state.value.popularFrees) - .catch { - Timber.e("CommunityViewModel syncPopularPost error $it") - } - .collectLatest { (reviews, frees) -> - Timber.e("CommunityViewModel syncPopularPost success $reviews $frees") + .onSuccess { setState { copy( - popularReviews = reviews, - popularFrees = frees + popularReviews = it.first, + popularFrees = it.second ) } } @@ -99,47 +92,42 @@ class CommunityViewModel @Inject constructor( private fun changeCategory(category: Category) { viewModelScope.launch { - getPostsUseCase(category, PostType.COMMUNITY_TAB_REVIEW, PostSubject.REVIEW) + val posts = getPostsUseCase(category, PostType.COMMUNITY_TAB_REVIEW, PostSubject.REVIEW) .onStart { setState { copy(category = category) } } .catch { - Timber.e("CommunityViewModel changeCategory error $it") - } - .collectLatest { - setState { copy(reviews = it.cachedIn(viewModelScope)) } + Timber.e("error $it") } + + setState { + copy(reviews = posts.cachedIn(viewModelScope)) + } } } private fun initData() { val currentCategory = state.value.category viewModelScope.launch { - combine( - combine( - getPostsUseCase(currentCategory, PostType.COMMUNITY_TAB_REVIEW, PostSubject.REVIEW), - getPopularPostsUseCase(category = currentCategory, PostSubject.REVIEW) - ) { reviewPosts, popularReviewPost -> - Pair(reviewPosts, popularReviewPost) - }, - combine( - getPostsUseCase(currentCategory, PostType.COMMUNITY_TAB_FREE, PostSubject.POST), - getPopularPostsUseCase(category = currentCategory, PostSubject.POST) - ) { reviewPosts, popularReviewPost -> - Pair(reviewPosts, popularReviewPost) + try { + val popularReviewPostsAsync = async { getPopularPostsUseCase(category = currentCategory, PostSubject.REVIEW) } + val popularPostsAsync = async { getPopularPostsUseCase(currentCategory, PostSubject.POST) } + + val reviewPosts = getPostsUseCase(currentCategory, PostType.COMMUNITY_TAB_REVIEW, PostSubject.REVIEW) + val posts = getPostsUseCase(currentCategory, PostType.COMMUNITY_TAB_FREE, PostSubject.POST) + + val popularReviewPosts = popularReviewPostsAsync.await() + val popularPosts = popularPostsAsync.await() + + setState { + CommunityUiState.initState.copy( + reviews = reviewPosts.cachedIn(viewModelScope), + popularReviews = popularReviewPosts.getOrThrow(), + frees = posts.cachedIn(viewModelScope), + popularFrees = popularPosts.getOrThrow() + ) } - ) { reviewInfo, freeInfo -> - CommunityUiState.initState.copy( - reviews = reviewInfo.first.cachedIn(viewModelScope), - popularReviews = reviewInfo.second, - frees = freeInfo.first.cachedIn(viewModelScope), - popularFrees = freeInfo.second - ) + } catch (e: BadRequestException) { + Timber.e("error : $e") } - .catch { - Timber.e("CommunityViewModel initData error $it") - } - .collectLatest { - setState { it } - } } } } diff --git a/feature/community/src/main/java/com/core/community/viewmodel/CommunityWriteViewModel.kt b/feature/community/src/main/java/com/core/community/viewmodel/CommunityWriteViewModel.kt index d82a9601..d34d4552 100644 --- a/feature/community/src/main/java/com/core/community/viewmodel/CommunityWriteViewModel.kt +++ b/feature/community/src/main/java/com/core/community/viewmodel/CommunityWriteViewModel.kt @@ -101,11 +101,7 @@ class CommunityWriteViewModel @Inject constructor( viewModelScope.launch { postModifyPostUseCase(postId, modifyPost) - .catch { - Timber.e("CommunityWriteViewModel postModify error $it") - } - .collectLatest { - Timber.e("CommunityWriteViewModel postModify success $it") + .onSuccess { postId -> setEffect { CommunityWriteUiEffect.Modify(postId) } } } @@ -115,10 +111,7 @@ class CommunityWriteViewModel @Inject constructor( postId?.let { id -> viewModelScope.launch { getPostDetailUseCase(id) - .catch { - Timber.e("CommunityWriteViewModel initData error $it") - } - .collectLatest { postDetail -> + .onSuccess { postDetail -> setState { copy( postId = id, @@ -187,11 +180,7 @@ class CommunityWriteViewModel @Inject constructor( ) viewModelScope.launch { postCreatePostUseCase(createPost) - .catch { - Timber.e("CommunityWriteViewModel postCreatePost error $it") - } - .collectLatest { - Timber.e("CommunityWriteViewModel postCreatePost success $it") + .onSuccess { setEffect { CommunityWriteUiEffect.CreatePost } } } @@ -225,11 +214,7 @@ class CommunityWriteViewModel @Inject constructor( private fun getImages() { viewModelScope.launch { getImageListUseCase() - .catch { - Timber.e("CommunityWriteViewModel getImages error $it") - } - .collectLatest { - Timber.e("CommunityWriteViewModel getImages success $it") + .onSuccess { setState { copy(images = it) } setEffect { CommunityWriteUiEffect.GoPictureScreen(it) } } diff --git a/feature/home/src/main/java/com/core/home/viewmodel/HomeViewModel.kt b/feature/home/src/main/java/com/core/home/viewmodel/HomeViewModel.kt index 79e9d77e..605ec579 100644 --- a/feature/home/src/main/java/com/core/home/viewmodel/HomeViewModel.kt +++ b/feature/home/src/main/java/com/core/home/viewmodel/HomeViewModel.kt @@ -49,10 +49,7 @@ class HomeViewModel @Inject constructor( private fun postPostScrap(postId: Long, scrap: Boolean) { viewModelScope.launch { postPostScrapUseCase(postId, scrap) - .catch { - Timber.e("HomeViewModel postPostScrap error $it") - } - .collectLatest { + .onSuccess { setState { copy( homeData = homeData.copy( diff --git a/feature/mypage/src/main/java/com/core/mypage/viewmodel/ScrapPostViewModel.kt b/feature/mypage/src/main/java/com/core/mypage/viewmodel/ScrapPostViewModel.kt index d6dddf45..23de2bed 100644 --- a/feature/mypage/src/main/java/com/core/mypage/viewmodel/ScrapPostViewModel.kt +++ b/feature/mypage/src/main/java/com/core/mypage/viewmodel/ScrapPostViewModel.kt @@ -13,11 +13,7 @@ import com.core.mypage.model.scrappost.ScrapPostUiState import com.core.navigation.model.ScrapPostType import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch -import timber.log.Timber @HiltViewModel class ScrapPostViewModel @Inject constructor( @@ -46,10 +42,7 @@ class ScrapPostViewModel @Inject constructor( private fun postScrapPost(postId: Long, scrap: Boolean) { viewModelScope.launch { postPostScrapUseCase(postId, scrap) - .catch { - Timber.e("ScrapPostViewModel postScrapPost error $it") - } - .collectLatest { + .onSuccess { val newCount = if (state.value.type == ScrapPostType.SCRAP) { state.value.count - 1 } else { @@ -65,10 +58,7 @@ class ScrapPostViewModel @Inject constructor( private fun refreshCount() { viewModelScope.launch { getSettingPostCountUseCase(state.value.type == ScrapPostType.SCRAP) - .catch { - Timber.e("ScrapPostViewModel refreshCount error $it") - } - .collectLatest { count -> + .onSuccess { count -> setState { copy(count = count) } @@ -78,20 +68,14 @@ class ScrapPostViewModel @Inject constructor( private fun initData(isScrap: Boolean, type: ScrapPostType) { viewModelScope.launch { - combine( - getSettingPostUseCase(isScrap), - getSettingPostCountUseCase(isScrap) - ) { posts, count -> - Pair(posts, count) - } - .catch { - Timber.e("ScrapPostViewModel initData error $it") - } - .collectLatest { (posts, count) -> + val settingPost = getSettingPostUseCase(isScrap) + + getSettingPostCountUseCase(isScrap) + .onSuccess { setState { copy( isLoading = false, - posts = posts.cachedIn(viewModelScope), + posts = settingPost.cachedIn(viewModelScope), type = type, count = count ) diff --git a/feature/mypage/src/main/java/com/core/mypage/viewmodel/SettingViewModel.kt b/feature/mypage/src/main/java/com/core/mypage/viewmodel/SettingViewModel.kt index 958839a8..c9a1f466 100644 --- a/feature/mypage/src/main/java/com/core/mypage/viewmodel/SettingViewModel.kt +++ b/feature/mypage/src/main/java/com/core/mypage/viewmodel/SettingViewModel.kt @@ -86,11 +86,8 @@ class SettingViewModel @Inject constructor( private fun getImages() { viewModelScope.launch { getImageListUseCase() - .catch { - Timber.e("SettingViewModel getImages error $it") - } - .collectLatest { - Timber.i("SettingViewModel getImages success $it") + .onSuccess { + Timber.i("success $it") setState { copy(images = it) } } } diff --git a/feature/search/src/main/java/com/youth/search/viewmodel/CommunitySearchViewModel.kt b/feature/search/src/main/java/com/youth/search/viewmodel/CommunitySearchViewModel.kt index d4487d9e..b9ee9bfa 100644 --- a/feature/search/src/main/java/com/youth/search/viewmodel/CommunitySearchViewModel.kt +++ b/feature/search/src/main/java/com/youth/search/viewmodel/CommunitySearchViewModel.kt @@ -54,11 +54,8 @@ class CommunitySearchViewModel @Inject constructor( private fun postPostScrap(postId: Long, scrap: Boolean) { viewModelScope.launch { postPostScrapUseCase(postId, scrap) - .catch { - Timber.e("HomeViewModel postPostScrap error $it") - } - .collectLatest { - Timber.e("HomeViewModel postPostScrap success $it") + .onSuccess { + Timber.e("success $it") } } }