diff --git a/android/app/src/main/java/com/app/edonymyeon/data/common/CustomThrowableUtils.kt b/android/app/src/main/java/com/app/edonymyeon/data/common/CustomThrowableUtils.kt deleted file mode 100644 index 208f5eaff..000000000 --- a/android/app/src/main/java/com/app/edonymyeon/data/common/CustomThrowableUtils.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.app.edonymyeon.data.common - -import org.json.JSONObject -import retrofit2.Response - -fun createCustomThrowableFromResponse(result: Response): CustomThrowable { - val errorResponse = result.errorBody()?.string() - val json = errorResponse?.let { JSONObject(it) } - val errorMessage = json?.getString("errorMessage") ?: "" - val errorCode = json?.getInt("errorCode") ?: 0 - return CustomThrowable(errorCode, errorMessage) -} diff --git a/android/app/src/main/java/com/app/edonymyeon/data/common/FetchState.kt b/android/app/src/main/java/com/app/edonymyeon/data/common/FetchState.kt index 350357556..726b40bc4 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/common/FetchState.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/common/FetchState.kt @@ -1,15 +1,17 @@ package com.app.edonymyeon.data.common +import com.app.edonymyeon.presentation.common.exception.HttpException + sealed interface FetchState { object BadInternet : FetchState object ParseError : FetchState object WrongConnection : FetchState class NoAuthorization( - val customThrowable: CustomThrowable, + val customThrowable: HttpException, ) : FetchState class Fail( - val customThrowable: CustomThrowable, + val customThrowable: HttpException, ) : FetchState } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/common/Result.kt b/android/app/src/main/java/com/app/edonymyeon/data/common/Result.kt deleted file mode 100644 index 5f0598171..000000000 --- a/android/app/src/main/java/com/app/edonymyeon/data/common/Result.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.app.edonymyeon.data.common - -sealed class Result { - - class Success(val data: T, val code: Int) : Result() - - class ApiError(val customThrowable: CustomThrowable) : Result() - - class UnKnownApiError(val code: Int) : Result() - - class NetworkError(val fetchState: FetchState) : Result() - - class NullResult : Result() -} diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/auth/AuthDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/auth/AuthDataSource.kt index 5c9c74e0b..7ca78a7fe 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/auth/AuthDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/auth/AuthDataSource.kt @@ -5,7 +5,7 @@ import com.app.edonymyeon.data.dto.request.LogoutRequest import com.app.edonymyeon.data.dto.request.TokenRequest import com.app.edonymyeon.data.dto.request.UserRegistrationRequest import com.app.edonymyeon.data.dto.response.AuthDuplicateResponse -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse interface AuthDataSource { @@ -17,12 +17,16 @@ interface AuthDataSource { interface Remote { suspend fun login( loginDataModel: LoginDataModel, - ): Response + ): ApiResponse - suspend fun loginByKakao(accessToken: TokenRequest): Response + suspend fun loginByKakao(accessToken: TokenRequest): ApiResponse - suspend fun signUp(userRegistrationRequest: UserRegistrationRequest): Response - suspend fun checkDuplicate(target: String, value: String): Response - suspend fun logout(logoutRequest: LogoutRequest): Response + suspend fun signUp(userRegistrationRequest: UserRegistrationRequest): ApiResponse + suspend fun checkDuplicate( + target: String, + value: String, + ): ApiResponse + + suspend fun logout(logoutRequest: LogoutRequest): ApiResponse } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/auth/AuthRemoteDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/auth/AuthRemoteDataSource.kt index 760f5f9b9..4bccdb284 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/auth/AuthRemoteDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/auth/AuthRemoteDataSource.kt @@ -6,33 +6,33 @@ import com.app.edonymyeon.data.dto.request.TokenRequest import com.app.edonymyeon.data.dto.request.UserRegistrationRequest import com.app.edonymyeon.data.dto.response.AuthDuplicateResponse import com.app.edonymyeon.data.service.AuthService -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import javax.inject.Inject class AuthRemoteDataSource @Inject constructor( private val authService: AuthService, ) : AuthDataSource.Remote { - override suspend fun signUp(userRegistrationRequest: UserRegistrationRequest): Response { + override suspend fun signUp(userRegistrationRequest: UserRegistrationRequest): ApiResponse { return authService.signUp(userRegistrationRequest) } override suspend fun checkDuplicate( target: String, value: String, - ): Response { + ): ApiResponse { return authService.checkDuplicate(target, value) } - override suspend fun login(loginDataModel: LoginDataModel): Response { + override suspend fun login(loginDataModel: LoginDataModel): ApiResponse { return authService.login(loginDataModel) } - override suspend fun logout(logoutRequest: LogoutRequest): Response { + override suspend fun logout(logoutRequest: LogoutRequest): ApiResponse { return authService.logout(logoutRequest) } - override suspend fun loginByKakao(accessToken: TokenRequest): Response { + override suspend fun loginByKakao(accessToken: TokenRequest): ApiResponse { return authService.loginByKakao(accessToken) } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/consumptions/ConsumptionsDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/consumptions/ConsumptionsDataSource.kt index a023f1bd5..32b6f4db9 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/consumptions/ConsumptionsDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/consumptions/ConsumptionsDataSource.kt @@ -1,8 +1,8 @@ package com.app.edonymyeon.data.datasource.consumptions import com.app.edonymyeon.data.dto.response.ConsumptionsResponse -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse interface ConsumptionsDataSource { - suspend fun getConsumptions(period: Int): Response + suspend fun getConsumptions(period: Int): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/consumptions/ConsumptionsRemoteDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/consumptions/ConsumptionsRemoteDataSource.kt index 719bbb324..147d799c0 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/consumptions/ConsumptionsRemoteDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/consumptions/ConsumptionsRemoteDataSource.kt @@ -2,14 +2,14 @@ package com.app.edonymyeon.data.datasource.consumptions import com.app.edonymyeon.data.dto.response.ConsumptionsResponse import com.app.edonymyeon.data.service.ConsumptionsService -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import javax.inject.Inject class ConsumptionsRemoteDataSource @Inject constructor( private val consumptionsService: ConsumptionsService, ) : ConsumptionsDataSource { - override suspend fun getConsumptions(period: Int): Response { + override suspend fun getConsumptions(period: Int): ApiResponse { return consumptionsService.getConsumptions(period) } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/notification/NotificationDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/notification/NotificationDataSource.kt index abf001f72..3a5e30520 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/notification/NotificationDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/notification/NotificationDataSource.kt @@ -1,8 +1,8 @@ package com.app.edonymyeon.data.datasource.notification import com.app.edonymyeon.data.dto.response.NotificationsResponse -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse interface NotificationDataSource { - suspend fun getNotifications(size: Int, page: Int): Response + suspend fun getNotifications(size: Int, page: Int): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/notification/NotificationRemoteDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/notification/NotificationRemoteDataSource.kt index e59fd997c..60f301179 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/notification/NotificationRemoteDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/notification/NotificationRemoteDataSource.kt @@ -2,14 +2,17 @@ package com.app.edonymyeon.data.datasource.notification import com.app.edonymyeon.data.dto.response.NotificationsResponse import com.app.edonymyeon.data.service.NotificationService -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import javax.inject.Inject class NotificationRemoteDataSource @Inject constructor( private val notificationService: NotificationService, ) : NotificationDataSource { - override suspend fun getNotifications(size: Int, page: Int): Response { + override suspend fun getNotifications( + size: Int, + page: Int, + ): ApiResponse { return notificationService.getNotifications(size, page) } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/post/PostDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/post/PostDataSource.kt index 45338429c..f92ff98ec 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/post/PostDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/post/PostDataSource.kt @@ -5,42 +5,42 @@ import com.app.edonymyeon.data.dto.response.CommentsResponse import com.app.edonymyeon.data.dto.response.PostDetailResponse import com.app.edonymyeon.data.dto.response.PostEditorResponse import com.app.edonymyeon.data.dto.response.Posts -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import java.io.File interface PostDataSource { suspend fun getPostDetail( postId: Long, notificationId: Long, - ): Response + ): ApiResponse - suspend fun deletePost(postId: Long): Response - suspend fun getPosts(size: Int, page: Int): Response + suspend fun deletePost(postId: Long): ApiResponse + suspend fun getPosts(size: Int, page: Int): ApiResponse suspend fun savePost( postEditorRequest: PostEditorRequest, imageFiles: List, - ): Response + ): ApiResponse suspend fun updatePost( id: Long, postEditorRequest: PostEditorRequest, imageUrls: List, imageFiles: List, - ): Response + ): ApiResponse - suspend fun getHotPosts(): Response + suspend fun getHotPosts(): ApiResponse - suspend fun getComments(postId: Long): Response + suspend fun getComments(postId: Long): ApiResponse suspend fun postComment( id: Long, image: File?, comment: String, - ): Response + ): ApiResponse suspend fun deleteComment( postId: Long, commentId: Long, - ): Response + ): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/post/PostRemoteDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/post/PostRemoteDataSource.kt index df3c59fc1..acc2e60ab 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/post/PostRemoteDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/post/PostRemoteDataSource.kt @@ -6,12 +6,12 @@ import com.app.edonymyeon.data.dto.response.PostDetailResponse import com.app.edonymyeon.data.dto.response.PostEditorResponse import com.app.edonymyeon.data.dto.response.Posts import com.app.edonymyeon.data.service.PostService +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MultipartBody import okhttp3.RequestBody import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody -import retrofit2.Response import java.io.File import javax.inject.Inject @@ -22,22 +22,22 @@ class PostRemoteDataSource @Inject constructor( override suspend fun getPostDetail( postId: Long, notificationId: Long, - ): Response { + ): ApiResponse { return postService.getPost(postId, notificationId) } - override suspend fun deletePost(postId: Long): Response { + override suspend fun deletePost(postId: Long): ApiResponse { return postService.deletePost(postId) } - override suspend fun getPosts(size: Int, page: Int): Response { + override suspend fun getPosts(size: Int, page: Int): ApiResponse { return postService.getPosts(size, page) } override suspend fun savePost( postEditorRequest: PostEditorRequest, imageFiles: List, - ): Response { + ): ApiResponse { val postEditorMap: HashMap = hashMapOf() postEditorMap["title"] = postEditorRequest.title.createRequestBody() @@ -55,7 +55,7 @@ class PostRemoteDataSource @Inject constructor( postEditorRequest: PostEditorRequest, imageUrls: List, imageFiles: List, - ): Response { + ): ApiResponse { val postEditorMap: HashMap = hashMapOf() postEditorMap["title"] = postEditorRequest.title.createRequestBody() @@ -69,15 +69,15 @@ class PostRemoteDataSource @Inject constructor( return postService.updatePost(id, postEditorMap, originalImages, newImages) } - override suspend fun getHotPosts(): Response { + override suspend fun getHotPosts(): ApiResponse { return postService.getHotPosts() } - override suspend fun getComments(postId: Long): Response { + override suspend fun getComments(postId: Long): ApiResponse { return postService.getComments(postId) } - override suspend fun postComment(id: Long, image: File?, comment: String): Response { + override suspend fun postComment(id: Long, image: File?, comment: String): ApiResponse { val requestFile = image?.asRequestBody("image/*".toMediaTypeOrNull()) val multipartFile = requestFile?.let { MultipartBody.Part.createFormData("image", image.name, it) } @@ -85,7 +85,7 @@ class PostRemoteDataSource @Inject constructor( return postService.postComment(id, if (image == null) null else multipartFile, requestBody) } - override suspend fun deleteComment(postId: Long, commentId: Long): Response { + override suspend fun deleteComment(postId: Long, commentId: Long): ApiResponse { return postService.deleteComment(postId, commentId) } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/preference/PreferenceDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/preference/PreferenceDataSource.kt index a29fc95a7..2774b26a0 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/preference/PreferenceDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/preference/PreferenceDataSource.kt @@ -2,10 +2,10 @@ package com.app.edonymyeon.data.datasource.preference import com.app.edonymyeon.data.dto.request.NotificationPreferenceRequest import com.app.edonymyeon.data.dto.response.NotificationPreferenceResponse -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse interface PreferenceDataSource { - suspend fun getNotificationPreference(): Response + suspend fun getNotificationPreference(): ApiResponse suspend fun saveNotificationPreference(notificationPreferenceRequest: NotificationPreferenceRequest): - Response + ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/preference/PreferenceRemoteDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/preference/PreferenceRemoteDataSource.kt index 0fa4df7ee..445bc0db1 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/preference/PreferenceRemoteDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/preference/PreferenceRemoteDataSource.kt @@ -3,18 +3,18 @@ package com.app.edonymyeon.data.datasource.preference import com.app.edonymyeon.data.dto.request.NotificationPreferenceRequest import com.app.edonymyeon.data.dto.response.NotificationPreferenceResponse import com.app.edonymyeon.data.service.PreferenceService -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import javax.inject.Inject class PreferenceRemoteDataSource @Inject constructor( private val preferenceService: PreferenceService, ) : PreferenceDataSource { - override suspend fun getNotificationPreference(): Response { + override suspend fun getNotificationPreference(): ApiResponse { return preferenceService.getNotificationPreference() } - override suspend fun saveNotificationPreference(notificationPreferenceRequest: NotificationPreferenceRequest): Response { + override suspend fun saveNotificationPreference(notificationPreferenceRequest: NotificationPreferenceRequest): ApiResponse { return preferenceService.saveNotificationPreference(notificationPreferenceRequest) } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/profile/ProfileDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/profile/ProfileDataSource.kt index bc10167d8..e74671dea 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/profile/ProfileDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/profile/ProfileDataSource.kt @@ -6,29 +6,29 @@ import com.app.edonymyeon.data.dto.request.PurchaseConfirmRequest import com.app.edonymyeon.data.dto.request.SavingConfirmRequest import com.app.edonymyeon.data.dto.response.AuthDuplicateResponse import com.app.edonymyeon.data.dto.response.MyPostsResponse -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import java.io.File interface ProfileDataSource { - suspend fun getMyPosts(page: Int, notificationId: Long): Response + suspend fun getMyPosts(page: Int, notificationId: Long): ApiResponse suspend fun postPurchaseConfirm( id: Long, purchaseConfirmRequest: PurchaseConfirmRequest, - ): Response + ): ApiResponse suspend fun postSavingConfirm( id: Long, savingConfirmRequest: SavingConfirmRequest, - ): Response + ): ApiResponse - suspend fun deleteConfirm(id: Long): Response - suspend fun getProfile(): Response - suspend fun withdraw(): Response + suspend fun deleteConfirm(id: Long): ApiResponse + suspend fun getProfile(): ApiResponse + suspend fun withdraw(): ApiResponse suspend fun updateProfile( profileRequest: ProfileUpdateRequest, newProfileImage: File?, - ): Response + ): ApiResponse - suspend fun checkDuplicate(target: String, value: String): Response + suspend fun checkDuplicate(target: String, value: String): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/profile/ProfileRemoteDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/profile/ProfileRemoteDataSource.kt index 287e7b534..125b9c5bf 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/profile/ProfileRemoteDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/profile/ProfileRemoteDataSource.kt @@ -7,11 +7,11 @@ import com.app.edonymyeon.data.dto.request.SavingConfirmRequest import com.app.edonymyeon.data.dto.response.AuthDuplicateResponse import com.app.edonymyeon.data.dto.response.MyPostsResponse import com.app.edonymyeon.data.service.ProfileService +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MultipartBody import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody -import retrofit2.Response import java.io.File import javax.inject.Inject @@ -19,40 +19,40 @@ class ProfileRemoteDataSource @Inject constructor( private val profileService: ProfileService, ) : ProfileDataSource { - override suspend fun getMyPosts(page: Int, notificationId: Long): Response { + override suspend fun getMyPosts(page: Int, notificationId: Long): ApiResponse { return profileService.getMyPost(20, page, notificationId) } override suspend fun postPurchaseConfirm( id: Long, purchaseConfirmRequest: PurchaseConfirmRequest, - ): Response { + ): ApiResponse { return profileService.postPurchaseConfirm(id, purchaseConfirmRequest) } override suspend fun postSavingConfirm( id: Long, savingConfirmRequest: SavingConfirmRequest, - ): Response { + ): ApiResponse { return profileService.postSavingConfirm(id, savingConfirmRequest) } - override suspend fun deleteConfirm(id: Long): Response { + override suspend fun deleteConfirm(id: Long): ApiResponse { return profileService.deleteConfirm(id) } - override suspend fun getProfile(): Response { + override suspend fun getProfile(): ApiResponse { return profileService.getProfile() } - override suspend fun withdraw(): Response { + override suspend fun withdraw(): ApiResponse { return profileService.withdraw() } override suspend fun updateProfile( profileRequest: ProfileUpdateRequest, newProfileImage: File?, - ): Response { + ): ApiResponse { val nickname = profileRequest.nickname.toRequestBody("text/plain".toMediaTypeOrNull()) return profileService.updateProfile( nickname, @@ -64,7 +64,7 @@ class ProfileRemoteDataSource @Inject constructor( override suspend fun checkDuplicate( target: String, value: String, - ): Response { + ): ApiResponse { return profileService.checkDuplicate(target, value) } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/recommend/RecommendDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/recommend/RecommendDataSource.kt index 1d7b04027..58f39fb43 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/recommend/RecommendDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/recommend/RecommendDataSource.kt @@ -1,10 +1,10 @@ package com.app.edonymyeon.data.datasource.recommend -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse interface RecommendDataSource { - suspend fun saveRecommendUp(postId: Long): Response - suspend fun deleteRecommendUp(postId: Long): Response - suspend fun saveRecommendDown(postId: Long): Response - suspend fun deleteRecommendDown(postId: Long): Response + suspend fun saveRecommendUp(postId: Long): ApiResponse + suspend fun deleteRecommendUp(postId: Long): ApiResponse + suspend fun saveRecommendDown(postId: Long): ApiResponse + suspend fun deleteRecommendDown(postId: Long): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/recommend/RecommendRemoteDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/recommend/RecommendRemoteDataSource.kt index 7a2f7954b..0623a41be 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/recommend/RecommendRemoteDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/recommend/RecommendRemoteDataSource.kt @@ -1,26 +1,26 @@ package com.app.edonymyeon.data.datasource.recommend import com.app.edonymyeon.data.service.RecommendService -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import javax.inject.Inject class RecommendRemoteDataSource @Inject constructor( private val recommendService: RecommendService, ) : RecommendDataSource { - override suspend fun saveRecommendUp(postId: Long): Response { + override suspend fun saveRecommendUp(postId: Long): ApiResponse { return recommendService.saveRecommendUp(postId) } - override suspend fun deleteRecommendUp(postId: Long): Response { + override suspend fun deleteRecommendUp(postId: Long): ApiResponse { return recommendService.deleteRecommendUp(postId) } - override suspend fun saveRecommendDown(postId: Long): Response { + override suspend fun saveRecommendDown(postId: Long): ApiResponse { return recommendService.saveRecommendDown(postId) } - override suspend fun deleteRecommendDown(postId: Long): Response { + override suspend fun deleteRecommendDown(postId: Long): ApiResponse { return recommendService.deleteRecommendDown(postId) } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/report/ReportDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/report/ReportDataSource.kt index 3a3a3326c..0b8283711 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/report/ReportDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/report/ReportDataSource.kt @@ -1,10 +1,10 @@ package com.app.edonymyeon.data.datasource.report import com.app.edonymyeon.data.dto.request.ReportRequest -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse interface ReportDataSource { suspend fun postReport( reportRequest: ReportRequest, - ): Response + ): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/report/ReportRemoteDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/report/ReportRemoteDataSource.kt index c6727faac..1aea77873 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/report/ReportRemoteDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/report/ReportRemoteDataSource.kt @@ -2,14 +2,14 @@ package com.app.edonymyeon.data.datasource.report import com.app.edonymyeon.data.dto.request.ReportRequest import com.app.edonymyeon.data.service.ReportService -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import javax.inject.Inject class ReportRemoteDataSource @Inject constructor( private val reportService: ReportService, ) : ReportDataSource { - override suspend fun postReport(reportRequest: ReportRequest): Response { + override suspend fun postReport(reportRequest: ReportRequest): ApiResponse { return reportService.postReport(reportRequest) } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/search/SearchDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/search/SearchDataSource.kt index bad45d746..00f51dfc5 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/search/SearchDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/search/SearchDataSource.kt @@ -1,8 +1,8 @@ package com.app.edonymyeon.data.datasource.search import com.app.edonymyeon.data.dto.response.Posts -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse interface SearchDataSource { - suspend fun getSearchResult(query: String, page: Int): Response + suspend fun getSearchResult(query: String, page: Int): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/datasource/search/SearchRemoteDataSource.kt b/android/app/src/main/java/com/app/edonymyeon/data/datasource/search/SearchRemoteDataSource.kt index a8eae78f3..515a19cc4 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/datasource/search/SearchRemoteDataSource.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/datasource/search/SearchRemoteDataSource.kt @@ -2,14 +2,14 @@ package com.app.edonymyeon.data.datasource.search import com.app.edonymyeon.data.dto.response.Posts import com.app.edonymyeon.data.service.SearchService -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import javax.inject.Inject class SearchRemoteDataSource @Inject constructor( private val searchService: SearchService, ) : SearchDataSource { - override suspend fun getSearchResult(query: String, page: Int): Response { + override suspend fun getSearchResult(query: String, page: Int): ApiResponse { return searchService.getSearchResult(query, RESULT_LOADING_SIZE, page) } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/repository/AuthRepositoryImpl.kt b/android/app/src/main/java/com/app/edonymyeon/data/repository/AuthRepositoryImpl.kt index 682d8a332..d94ecce5b 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/repository/AuthRepositoryImpl.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/repository/AuthRepositoryImpl.kt @@ -1,12 +1,11 @@ package com.app.edonymyeon.data.repository -import com.app.edonymyeon.data.common.createCustomThrowableFromResponse import com.app.edonymyeon.data.datasource.auth.AuthDataSource import com.app.edonymyeon.data.dto.LoginDataModel import com.app.edonymyeon.data.dto.request.LogoutRequest import com.app.edonymyeon.data.dto.request.TokenRequest -import com.app.edonymyeon.data.dto.response.AuthDuplicateResponse import com.app.edonymyeon.mapper.toDataModel +import com.app.edonymyeon.mapper.toResult import com.domain.edonymyeon.model.UserRegistration import com.domain.edonymyeon.repository.AuthRepository import javax.inject.Inject @@ -25,63 +24,37 @@ class AuthRepositoryImpl @Inject constructor( } override suspend fun signUp(userRegistration: UserRegistration): Result { - val result = authRemoteDataSource.signUp( + return authRemoteDataSource.signUp( userRegistration.toDataModel(), - ) - return if (result.isSuccessful) { - Result.success(Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + ).toResult() } override suspend fun checkDuplicate( target: String, value: String, ): Result { - val result = authRemoteDataSource.checkDuplicate(target, value) - - return if (result.isSuccessful) { - Result.success((result.body() ?: AuthDuplicateResponse(false)).isUnique) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) + return authRemoteDataSource.checkDuplicate(target, value).toResult { it, _ -> + it.isUnique } } override suspend fun login(email: String, password: String, deviceToken: String): Result { - val result = authRemoteDataSource.login(LoginDataModel(email, password, deviceToken)) - - return if (result.isSuccessful) { - authLocalDataSource.setAuthToken(result.headers()["Set-Cookie"] as String) - Result.success(result.body() ?: Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return authRemoteDataSource.login(LoginDataModel(email, password, deviceToken)) + .toResult { _, headers -> + authLocalDataSource.setAuthToken(headers["Set-Cookie"] as String) + } } override suspend fun loginByKakao(accessToken: String, deviceToken: String): Result { - val result = authRemoteDataSource.loginByKakao(TokenRequest(accessToken, deviceToken)) - - return if (result.isSuccessful) { - authLocalDataSource.setAuthToken(result.headers()["Set-Cookie"] as String) - Result.success(result.body() ?: Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return authRemoteDataSource.loginByKakao(TokenRequest(accessToken, deviceToken)) + .toResult { _, headers -> + authLocalDataSource.setAuthToken(headers["Set-Cookie"] as String) + } } override suspend fun logout(deviceToken: String): Result { - val result = authRemoteDataSource.logout(LogoutRequest(deviceToken)) - return if (result.isSuccessful) { + return authRemoteDataSource.logout(LogoutRequest(deviceToken)).toResult { _, _ -> authLocalDataSource.setAuthToken(null) - Result.success(Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) } } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/repository/ConsumptionsRepositoryImpl.kt b/android/app/src/main/java/com/app/edonymyeon/data/repository/ConsumptionsRepositoryImpl.kt index b48420721..4faf4b365 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/repository/ConsumptionsRepositoryImpl.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/repository/ConsumptionsRepositoryImpl.kt @@ -1,9 +1,8 @@ package com.app.edonymyeon.data.repository -import com.app.edonymyeon.data.common.createCustomThrowableFromResponse import com.app.edonymyeon.data.datasource.consumptions.ConsumptionsDataSource -import com.app.edonymyeon.data.dto.response.ConsumptionsResponse import com.app.edonymyeon.mapper.toDomain +import com.app.edonymyeon.mapper.toResult import com.domain.edonymyeon.repository.ConsumptionsRepository import javax.inject.Inject @@ -11,13 +10,8 @@ class ConsumptionsRepositoryImpl @Inject constructor( private val consumptionsDataSource: ConsumptionsDataSource, ) : ConsumptionsRepository { override suspend fun getConsumptions(period: Int): Result { - val result = consumptionsDataSource.getConsumptions(period) - - return if (result.isSuccessful) { - Result.success((result.body() as ConsumptionsResponse).toDomain()) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) + return consumptionsDataSource.getConsumptions(period).toResult { it, _ -> + it.toDomain() } } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/repository/NotificationRepositoryImpl.kt b/android/app/src/main/java/com/app/edonymyeon/data/repository/NotificationRepositoryImpl.kt index 1bb860607..416a4ccb9 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/repository/NotificationRepositoryImpl.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/repository/NotificationRepositoryImpl.kt @@ -1,8 +1,8 @@ package com.app.edonymyeon.data.repository -import com.app.edonymyeon.data.common.createCustomThrowableFromResponse import com.app.edonymyeon.data.datasource.notification.NotificationDataSource import com.app.edonymyeon.mapper.toDomain +import com.app.edonymyeon.mapper.toResult import com.domain.edonymyeon.model.Notifications import com.domain.edonymyeon.repository.NotificationRepository import javax.inject.Inject @@ -10,12 +10,8 @@ import javax.inject.Inject class NotificationRepositoryImpl @Inject constructor(private val notificationDataSource: NotificationDataSource) : NotificationRepository { override suspend fun getNotifications(size: Int, page: Int): Result { - val result = notificationDataSource.getNotifications(size, page) - return if (result.isSuccessful && result.body() != null) { - Result.success(result.body()!!.toDomain()) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) + return notificationDataSource.getNotifications(size, page).toResult { it, _ -> + it.toDomain() } } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/repository/PostRepositoryImpl.kt b/android/app/src/main/java/com/app/edonymyeon/data/repository/PostRepositoryImpl.kt index d9eb8d325..14523ce8e 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/repository/PostRepositoryImpl.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/repository/PostRepositoryImpl.kt @@ -1,12 +1,9 @@ package com.app.edonymyeon.data.repository -import com.app.edonymyeon.data.common.createCustomThrowableFromResponse import com.app.edonymyeon.data.datasource.post.PostDataSource -import com.app.edonymyeon.data.dto.response.CommentsResponse -import com.app.edonymyeon.data.dto.response.PostDetailResponse -import com.app.edonymyeon.data.dto.response.PostEditorResponse import com.app.edonymyeon.mapper.toDataModel import com.app.edonymyeon.mapper.toDomain +import com.app.edonymyeon.mapper.toResult import com.domain.edonymyeon.model.Comments import com.domain.edonymyeon.model.PostEditor import com.domain.edonymyeon.model.PostItems @@ -18,39 +15,23 @@ class PostRepositoryImpl @Inject constructor( private val postDataSource: PostDataSource, ) : PostRepository { override suspend fun getPostDetail(postId: Long, notificationId: Long): Result { - val result = postDataSource.getPostDetail(postId, notificationId) - return if (result.isSuccessful) { - Result.success((result.body() as PostDetailResponse).toDomain()) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) + return postDataSource.getPostDetail(postId, notificationId).toResult { it, _ -> + it.toDomain() } } override suspend fun deletePost(postId: Long): Result { - val result = postDataSource.deletePost(postId) - return if (result.isSuccessful) { - Result.success(Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return postDataSource.deletePost(postId).toResult() } override suspend fun getPosts(size: Int, page: Int): Result { - val result = postDataSource.getPosts(size, page) - return if (result.isSuccessful && result.body() != null) { - Result.success( - PostItems( - result.body()!!.post.map { - it.toDomain() - }, - result.body()!!.isLast, - ), + return postDataSource.getPosts(size, page).toResult { postItems, _ -> + PostItems( + postItems.post.map { + it.toDomain() + }, + postItems.isLast, ) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) } } @@ -58,13 +39,7 @@ class PostRepositoryImpl @Inject constructor( postEditor: PostEditor, images: List, ): Result { - val result = postDataSource.savePost(postEditor.toDataModel(), images) - return if (result.isSuccessful) { - Result.success(result.body() as PostEditorResponse) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return postDataSource.savePost(postEditor.toDataModel(), images).toResult() } override suspend fun updatePost( @@ -73,68 +48,37 @@ class PostRepositoryImpl @Inject constructor( imageUrls: List, imageFiles: List, ): Result { - val result = - postDataSource.updatePost(postId, postEditor.toDataModel(), imageUrls, imageFiles) - return if (result.isSuccessful) { - Result.success(result.body() as PostEditorResponse) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return postDataSource.updatePost(postId, postEditor.toDataModel(), imageUrls, imageFiles) + .toResult() } override suspend fun getHotPosts(): Result { - val result = postDataSource.getHotPosts() - return if (result.isSuccessful && result.body() != null) { - Result.success( - PostItems( - result.body()!!.post.map { - it.toDomain() - }, - result.body()!!.isLast, - ), + return postDataSource.getHotPosts().toResult { it, _ -> + PostItems( + it.post.map { post -> + post.toDomain() + }, + it.isLast, ) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) } } override suspend fun getComments(postId: Long): Result { - val result = postDataSource.getComments(postId) - return if (result.isSuccessful && result.body() != null) { - val body = result.body() - Result.success( - Comments( - body?.commentCount ?: 0, - (body as CommentsResponse).comments.map { - it.toDomain() - }, - ), + return postDataSource.getComments(postId).toResult { it, _ -> + Comments( + it.commentCount, + it.comments.map { commentData -> + commentData.toDomain() + }, ) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) } } override suspend fun postComment(id: Long, image: File?, comment: String): Result { - val result = postDataSource.postComment(id, image, comment) - return if (result.isSuccessful) { - Result.success(Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return postDataSource.postComment(id, image, comment).toResult() } override suspend fun deleteComment(postId: Long, commentId: Long): Result { - val result = postDataSource.deleteComment(postId, commentId) - return if (result.isSuccessful) { - Result.success(Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return postDataSource.deleteComment(postId, commentId).toResult() } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/repository/PreferenceRepositoryImpl.kt b/android/app/src/main/java/com/app/edonymyeon/data/repository/PreferenceRepositoryImpl.kt index 7933c940d..548381e01 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/repository/PreferenceRepositoryImpl.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/repository/PreferenceRepositoryImpl.kt @@ -1,9 +1,9 @@ package com.app.edonymyeon.data.repository -import com.app.edonymyeon.data.common.createCustomThrowableFromResponse import com.app.edonymyeon.data.datasource.preference.PreferenceDataSource import com.app.edonymyeon.data.dto.request.NotificationPreferenceRequest import com.app.edonymyeon.mapper.toDomain +import com.app.edonymyeon.mapper.toResult import com.domain.edonymyeon.model.NotificationPreference import com.domain.edonymyeon.repository.PreferenceRepository import javax.inject.Inject @@ -12,32 +12,20 @@ class PreferenceRepositoryImpl @Inject constructor( private val preferenceDataSource: PreferenceDataSource, ) : PreferenceRepository { override suspend fun getNotificationPreference(): Result> { - val result = preferenceDataSource.getNotificationPreference() - return if (result.isSuccessful && result.body() != null) { - Result.success( - (result.body()!!.notifications).map { - it.toDomain() - }, - ) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) + return preferenceDataSource.getNotificationPreference().toResult { it, _ -> + it.notifications.map { notification -> + notification.toDomain() + } } } override suspend fun saveNotificationPreference(preferenceType: String): Result> { - val result = preferenceDataSource.saveNotificationPreference( + return preferenceDataSource.saveNotificationPreference( NotificationPreferenceRequest(preferenceType), - ) - return if (result.isSuccessful && result.body() != null) { - Result.success( - (result.body()!!.notifications).map { - it.toDomain() - }, - ) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) + ).toResult { it, _ -> + it.notifications.map { notification -> + notification.toDomain() + } } } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/repository/ProfileRepositoryImpl.kt b/android/app/src/main/java/com/app/edonymyeon/data/repository/ProfileRepositoryImpl.kt index 27a490143..5acf3366c 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/repository/ProfileRepositoryImpl.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/repository/ProfileRepositoryImpl.kt @@ -1,14 +1,11 @@ package com.app.edonymyeon.data.repository -import com.app.edonymyeon.data.common.createCustomThrowableFromResponse import com.app.edonymyeon.data.datasource.profile.ProfileDataSource -import com.app.edonymyeon.data.dto.WriterDataModel import com.app.edonymyeon.data.dto.request.ProfileUpdateRequest import com.app.edonymyeon.data.dto.request.PurchaseConfirmRequest import com.app.edonymyeon.data.dto.request.SavingConfirmRequest -import com.app.edonymyeon.data.dto.response.AuthDuplicateResponse -import com.app.edonymyeon.data.dto.response.MyPostsResponse import com.app.edonymyeon.mapper.toDomain +import com.app.edonymyeon.mapper.toResult import com.domain.edonymyeon.model.MyPosts import com.domain.edonymyeon.model.Nickname import com.domain.edonymyeon.model.Writer @@ -20,17 +17,13 @@ class ProfileRepositoryImpl @Inject constructor( private val profileDataSource: ProfileDataSource, ) : ProfileRepository { override suspend fun getMyPosts(page: Int, notificationId: Long): Result { - val result = profileDataSource.getMyPosts(page, notificationId) - return if (result.isSuccessful) { - Result.success( - MyPosts( - (result.body() as MyPostsResponse).posts.map { it.toDomain() }, - result.body()!!.isLast, - ), + return profileDataSource.getMyPosts(page, notificationId).toResult { it, _ -> + MyPosts( + it.posts.map { post -> + post.toDomain() + }, + it.isLast, ) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) } } @@ -40,56 +33,28 @@ class ProfileRepositoryImpl @Inject constructor( year: Int, month: Int, ): Result { - val result = profileDataSource.postPurchaseConfirm( + return profileDataSource.postPurchaseConfirm( id, PurchaseConfirmRequest(purchasePrice, year, month), - ) - return if (result.isSuccessful) { - Result.success((result.body() ?: Unit)) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + ).toResult() } override suspend fun postSavingConfirm(id: Long, year: Int, month: Int): Result { - val result = profileDataSource.postSavingConfirm(id, SavingConfirmRequest(year, month)) - return if (result.isSuccessful) { - Result.success((result.body() ?: Unit)) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return profileDataSource.postSavingConfirm(id, SavingConfirmRequest(year, month)).toResult() } override suspend fun deleteConfirm(id: Long): Result { - val result = profileDataSource.deleteConfirm(id) - return if (result.isSuccessful) { - Result.success((result.body() ?: Unit)) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return profileDataSource.deleteConfirm(id).toResult() } override suspend fun getProfile(): Result { - val result = profileDataSource.getProfile() - return if (result.isSuccessful) { - Result.success((result.body() as WriterDataModel).toDomain()) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) + return profileDataSource.getProfile().toResult { it, _ -> + it.toDomain() } } override suspend fun withdraw(): Result { - val result = profileDataSource.withdraw() - return if (result.isSuccessful) { - Result.success(result.body() ?: Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return profileDataSource.withdraw().toResult() } override suspend fun updateProfile( @@ -97,32 +62,19 @@ class ProfileRepositoryImpl @Inject constructor( profileImage: File?, isProfileChanged: Boolean, ): Result { - val result = profileDataSource.updateProfile( + return profileDataSource.updateProfile( ProfileUpdateRequest( nickname.value, isProfileChanged, ), profileImage, - ) - return if (result.isSuccessful) { - Result.success(result.body() ?: Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + ).toResult() } override suspend fun checkDuplicate( target: String, value: String, ): Result { - val result = profileDataSource.checkDuplicate(target, value) - - return if (result.isSuccessful) { - Result.success((result.body() ?: AuthDuplicateResponse(false)).isUnique) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return profileDataSource.checkDuplicate(target, value).toResult() } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/repository/RecommendRepositoryImpl.kt b/android/app/src/main/java/com/app/edonymyeon/data/repository/RecommendRepositoryImpl.kt index 3065515db..1088efcf6 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/repository/RecommendRepositoryImpl.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/repository/RecommendRepositoryImpl.kt @@ -1,7 +1,7 @@ package com.app.edonymyeon.data.repository -import com.app.edonymyeon.data.common.createCustomThrowableFromResponse import com.app.edonymyeon.data.datasource.recommend.RecommendDataSource +import com.app.edonymyeon.mapper.toResult import com.domain.edonymyeon.repository.RecommendRepository import javax.inject.Inject @@ -9,46 +9,18 @@ class RecommendRepositoryImpl @Inject constructor( private val recommendDataSource: RecommendDataSource, ) : RecommendRepository { override suspend fun saveRecommendUp(postId: Long): Result { - val result = recommendDataSource.saveRecommendUp(postId) - - return if (result.isSuccessful) { - Result.success(Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return recommendDataSource.saveRecommendUp(postId).toResult() } override suspend fun deleteRecommendUp(postId: Long): Result { - val result = recommendDataSource.deleteRecommendUp(postId) - - return if (result.isSuccessful) { - Result.success(Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return recommendDataSource.deleteRecommendUp(postId).toResult() } override suspend fun saveRecommendDown(postId: Long): Result { - val result = recommendDataSource.saveRecommendDown(postId) - - return if (result.isSuccessful) { - Result.success(Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return recommendDataSource.saveRecommendDown(postId).toResult() } override suspend fun deleteRecommendDown(postId: Long): Result { - val result = recommendDataSource.deleteRecommendDown(postId) - - return if (result.isSuccessful) { - Result.success(Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + return recommendDataSource.deleteRecommendDown(postId).toResult() } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/repository/ReportRepositoryImpl.kt b/android/app/src/main/java/com/app/edonymyeon/data/repository/ReportRepositoryImpl.kt index 3c5a0b213..afee1b5db 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/repository/ReportRepositoryImpl.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/repository/ReportRepositoryImpl.kt @@ -1,8 +1,8 @@ package com.app.edonymyeon.data.repository -import com.app.edonymyeon.data.common.createCustomThrowableFromResponse import com.app.edonymyeon.data.datasource.report.ReportDataSource import com.app.edonymyeon.data.dto.request.ReportRequest +import com.app.edonymyeon.mapper.toResult import com.domain.edonymyeon.repository.ReportRepository import javax.inject.Inject @@ -14,20 +14,13 @@ class ReportRepositoryImpl @Inject constructor(private val reportDataSource: Rep repostId: Int, content: String?, ): Result { - val result = reportDataSource.postReport( + return reportDataSource.postReport( ReportRequest( type, postId, repostId, content, ), - ) - - return if (result.isSuccessful) { - Result.success(result.body() ?: Unit) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) - } + ).toResult() } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/repository/SearchRepositoryImpl.kt b/android/app/src/main/java/com/app/edonymyeon/data/repository/SearchRepositoryImpl.kt index 044af56e9..d709207bd 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/repository/SearchRepositoryImpl.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/repository/SearchRepositoryImpl.kt @@ -1,8 +1,8 @@ package com.app.edonymyeon.data.repository -import com.app.edonymyeon.data.common.createCustomThrowableFromResponse import com.app.edonymyeon.data.datasource.search.SearchDataSource import com.app.edonymyeon.mapper.toDomain +import com.app.edonymyeon.mapper.toResult import com.domain.edonymyeon.model.PostItems import com.domain.edonymyeon.repository.SearchRepository import javax.inject.Inject @@ -11,19 +11,13 @@ class SearchRepositoryImpl @Inject constructor( private val searchDataSource: SearchDataSource, ) : SearchRepository { override suspend fun getSearchResult(query: String, page: Int): Result { - val result = searchDataSource.getSearchResult(query, page) - return if (result.isSuccessful && result.body() != null) { - Result.success( - PostItems( - result.body()!!.post.map { - it.toDomain() - }, - result.body()!!.isLast, - ), + return searchDataSource.getSearchResult(query, page).toResult { it, _ -> + PostItems( + it.post.map { post -> + post.toDomain() + }, + it.isLast, ) - } else { - val customThrowable = createCustomThrowableFromResponse(result) - Result.failure(customThrowable) } } } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/AuthService.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/AuthService.kt index b81c05f9f..6ca1bb9fe 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/service/AuthService.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/AuthService.kt @@ -5,7 +5,7 @@ import com.app.edonymyeon.data.dto.request.LogoutRequest import com.app.edonymyeon.data.dto.request.TokenRequest import com.app.edonymyeon.data.dto.request.UserRegistrationRequest import com.app.edonymyeon.data.dto.response.AuthDuplicateResponse -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.POST @@ -13,26 +13,26 @@ import retrofit2.http.Query interface AuthService { @POST("/join") - suspend fun signUp(@Body userRegistrationRequest: UserRegistrationRequest): Response + suspend fun signUp(@Body userRegistrationRequest: UserRegistrationRequest): ApiResponse @GET("/join") suspend fun checkDuplicate( @Query("target") target: String, @Query("value") value: String, - ): Response + ): ApiResponse @POST("/login") suspend fun login( @Body loginDataModel: LoginDataModel, - ): Response + ): ApiResponse @POST("/auth/kakao/login") suspend fun loginByKakao( @Body accessToken: TokenRequest, - ): Response + ): ApiResponse @POST("/logout") suspend fun logout( @Body logoutRequest: LogoutRequest, - ): Response + ): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/ConsumptionsService.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/ConsumptionsService.kt index ea847afcd..f74f40c1e 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/service/ConsumptionsService.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/ConsumptionsService.kt @@ -1,11 +1,11 @@ package com.app.edonymyeon.data.service import com.app.edonymyeon.data.dto.response.ConsumptionsResponse -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import retrofit2.http.GET import retrofit2.http.Query interface ConsumptionsService { @GET("/consumptions") - suspend fun getConsumptions(@Query("period-month") period: Int): Response + suspend fun getConsumptions(@Query("period-month") period: Int): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/NotificationService.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/NotificationService.kt index 914fcbb87..a87e73c88 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/service/NotificationService.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/NotificationService.kt @@ -1,7 +1,7 @@ package com.app.edonymyeon.data.service import com.app.edonymyeon.data.dto.response.NotificationsResponse -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import retrofit2.http.GET import retrofit2.http.Query @@ -10,5 +10,5 @@ interface NotificationService { suspend fun getNotifications( @Query("size") size: Int, @Query("page") page: Int, - ): Response + ): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/PostService.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/PostService.kt index f338da653..4f33e1c80 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/service/PostService.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/PostService.kt @@ -4,9 +4,9 @@ import com.app.edonymyeon.data.dto.response.CommentsResponse import com.app.edonymyeon.data.dto.response.PostDetailResponse import com.app.edonymyeon.data.dto.response.PostEditorResponse import com.app.edonymyeon.data.dto.response.Posts +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.Response import retrofit2.http.DELETE import retrofit2.http.GET import retrofit2.http.Multipart @@ -22,23 +22,23 @@ interface PostService { suspend fun getPost( @Path("postId") postId: Long, @Query("notificated") notificated: Long, - ): Response + ): ApiResponse @DELETE("/posts/{postId}") - suspend fun deletePost(@Path("postId") postId: Long): Response + suspend fun deletePost(@Path("postId") postId: Long): ApiResponse @GET("/posts") suspend fun getPosts( @Query("size") size: Int, @Query("page") page: Int, - ): Response + ): ApiResponse @Multipart @POST("/posts") suspend fun savePost( @PartMap postEditorRequest: HashMap, @Part newImages: List, - ): Response + ): ApiResponse @Multipart @PUT("/posts/{postId}") @@ -47,15 +47,15 @@ interface PostService { @PartMap postEditorRequest: HashMap, @Part originalImages: List, @Part newImages: List, - ): Response + ): ApiResponse @GET("/posts/hot") - suspend fun getHotPosts(): Response + suspend fun getHotPosts(): ApiResponse @GET("/posts/{postId}/comments") suspend fun getComments( @Path("postId") postId: Long, - ): Response + ): ApiResponse @Multipart @POST("/posts/{postId}/comments") @@ -63,11 +63,11 @@ interface PostService { @Path("postId") postId: Long, @Part image: MultipartBody.Part?, @Part("comment") comment: RequestBody, - ): Response + ): ApiResponse @DELETE("/posts/{postId}/comments/{commentId}") suspend fun deleteComment( @Path("postId") postId: Long, @Path("commentId") commentId: Long, - ): Response + ): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/PreferenceService.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/PreferenceService.kt index 65a40f51f..4a9390e89 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/service/PreferenceService.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/PreferenceService.kt @@ -2,17 +2,17 @@ package com.app.edonymyeon.data.service import com.app.edonymyeon.data.dto.request.NotificationPreferenceRequest import com.app.edonymyeon.data.dto.response.NotificationPreferenceResponse -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.POST interface PreferenceService { @GET("/preference/notification") - suspend fun getNotificationPreference(): Response + suspend fun getNotificationPreference(): ApiResponse @POST("/preference/notification") suspend fun saveNotificationPreference( @Body notificationPreferenceRequest: NotificationPreferenceRequest, - ): Response + ): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/ProfileService.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/ProfileService.kt index d533be28a..476e95f36 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/service/ProfileService.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/ProfileService.kt @@ -5,9 +5,9 @@ import com.app.edonymyeon.data.dto.request.PurchaseConfirmRequest import com.app.edonymyeon.data.dto.request.SavingConfirmRequest import com.app.edonymyeon.data.dto.response.AuthDuplicateResponse import com.app.edonymyeon.data.dto.response.MyPostsResponse +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.Response import retrofit2.http.Body import retrofit2.http.DELETE import retrofit2.http.GET @@ -25,30 +25,30 @@ interface ProfileService { @Query("size") size: Int, @Query("page") page: Int, @Query("notificated") notificated: Long, - ): Response + ): ApiResponse @POST("/profile/my-posts/{postId}/purchase-confirm") suspend fun postPurchaseConfirm( @Path("postId") postId: Long, @Body purchaseConfirmRequest: PurchaseConfirmRequest, - ): Response + ): ApiResponse @POST("/profile/my-posts/{postId}/saving-confirm") suspend fun postSavingConfirm( @Path("postId") postId: Long, @Body savingConfirmRequest: SavingConfirmRequest, - ): Response + ): ApiResponse @DELETE("/profile/my-posts/{postId}/confirm-remove") suspend fun deleteConfirm( @Path("postId") postId: Long, - ): Response + ): ApiResponse @GET("/profile") - suspend fun getProfile(): Response + suspend fun getProfile(): ApiResponse @DELETE("/withdraw") - suspend fun withdraw(): Response + suspend fun withdraw(): ApiResponse @Multipart @PUT("/profile") @@ -56,11 +56,11 @@ interface ProfileService { @Part("nickname") nickname: RequestBody, @Part("isImageChanged") isImageChanged: Boolean, @Part image: MultipartBody.Part?, - ): Response + ): ApiResponse @GET("/profile/check-duplicate") suspend fun checkDuplicate( @Query("target") target: String, @Query("value") value: String, - ): Response + ): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/RecommendService.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/RecommendService.kt index 3be772732..95e6f6b71 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/service/RecommendService.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/RecommendService.kt @@ -1,20 +1,20 @@ package com.app.edonymyeon.data.service -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import retrofit2.http.DELETE import retrofit2.http.PUT import retrofit2.http.Path interface RecommendService { @PUT("/posts/{postId}/up") - suspend fun saveRecommendUp(@Path("postId") postId: Long): Response + suspend fun saveRecommendUp(@Path("postId") postId: Long): ApiResponse @DELETE("/posts/{postId}/up") - suspend fun deleteRecommendUp(@Path("postId") postId: Long): Response + suspend fun deleteRecommendUp(@Path("postId") postId: Long): ApiResponse @PUT("/posts/{postId}/down") - suspend fun saveRecommendDown(@Path("postId") postId: Long): Response + suspend fun saveRecommendDown(@Path("postId") postId: Long): ApiResponse @DELETE("/posts/{postId}/down") - suspend fun deleteRecommendDown(@Path("postId") postId: Long): Response + suspend fun deleteRecommendDown(@Path("postId") postId: Long): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/ReportService.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/ReportService.kt index d25a6cf4e..0dddd3451 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/service/ReportService.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/ReportService.kt @@ -1,7 +1,7 @@ package com.app.edonymyeon.data.service import com.app.edonymyeon.data.dto.request.ReportRequest -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import retrofit2.http.Body import retrofit2.http.POST @@ -9,5 +9,5 @@ interface ReportService { @POST("report") suspend fun postReport( @Body reportRequest: ReportRequest, - ): Response + ): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/SearchService.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/SearchService.kt index 5cd8c7233..295ce6a4a 100644 --- a/android/app/src/main/java/com/app/edonymyeon/data/service/SearchService.kt +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/SearchService.kt @@ -1,7 +1,7 @@ package com.app.edonymyeon.data.service import com.app.edonymyeon.data.dto.response.Posts -import retrofit2.Response +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse import retrofit2.http.GET import retrofit2.http.Query @@ -11,5 +11,5 @@ interface SearchService { @Query("query") query: String, @Query("size") size: Int, @Query("page") page: Int, - ): Response + ): ApiResponse } diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/ApiResponse.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/ApiResponse.kt new file mode 100644 index 000000000..21413c52b --- /dev/null +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/ApiResponse.kt @@ -0,0 +1,32 @@ +package com.app.edonymyeon.data.service.client.calladapter + +sealed interface ApiResponse { + data class Success(val data: T, val headers: okhttp3.Headers) : ApiResponse + + sealed interface Failure : ApiResponse { + data class HttpError( + val errorResponse: ErrorResponse, + ) : Failure + + data class NoAuthError( + val errorResponse: ErrorResponse, + ) : Failure + + data class NetworkError(val throwable: Throwable) : Failure + data class UnknownApiError(val throwable: Throwable) : Failure + } +} + +inline fun ApiResponse.onSuccess( + action: (value: T) -> Unit, +): ApiResponse { + if (this is ApiResponse.Success) action(data) + return this +} + +inline fun ApiResponse.onFailure( + action: (error: ApiResponse.Failure) -> Unit, +): ApiResponse { + if (this is ApiResponse.Failure) action(this) + return this +} diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/EdonymyeonCall.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/EdonymyeonCall.kt new file mode 100644 index 000000000..9fc1cc35a --- /dev/null +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/EdonymyeonCall.kt @@ -0,0 +1,90 @@ +package com.app.edonymyeon.data.service.client.calladapter + +import com.google.gson.Gson +import okhttp3.Request +import okio.Timeout +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import java.io.IOException +import java.lang.reflect.Type + +class EdonymyeonCall( + private val delegate: Call, + private val successType: Type, +) : Call> { + override fun enqueue(callback: Callback>) = delegate.enqueue( + object : Callback { + override fun onResponse(call: Call, response: Response) { + callback.onResponse(this@EdonymyeonCall, Response.success(response.toApiResult())) + } + + override fun onFailure(call: Call, throwable: Throwable) { + val error = if (throwable is IOException) { + ApiResponse.Failure.NetworkError(throwable) + } else { + ApiResponse.Failure.UnknownApiError(throwable) + } + callback.onResponse(this@EdonymyeonCall, Response.success(error)) + } + }, + + ) + + private fun Response.toApiResult(): ApiResponse { + if (!isSuccessful) { + val errorBody = + Gson().fromJson(errorBody()?.charStream(), ErrorResponse::class.java) + if (errorBody.errorCode == ERROR_AUTHORIZATION_CODE) { + return ApiResponse.Failure.NoAuthError( + errorBody, + ) + } + return ApiResponse.Failure.HttpError( + errorBody, + ) + } + + body()?.let { body -> + return ApiResponse.Success(body, headers()) + } + + return if (successType == Unit::class.java) { + @Suppress("UNCHECKED_CAST") + ( + ApiResponse.Success( + Unit as T, + headers(), + ) + ) + } else { + ApiResponse.Failure.UnknownApiError( + IllegalStateException( + ERROR_BODY_NOT_EXIST, + ), + ) + } + } + + override fun clone(): Call> = EdonymyeonCall(delegate.clone(), successType) + + override fun execute(): Response> { + throw UnsupportedOperationException(ERROR_UNSUPPORTED_EXCEPTION) + } + + override fun isExecuted(): Boolean = delegate.isExecuted + + override fun cancel() = delegate.cancel() + + override fun isCanceled(): Boolean = delegate.isCanceled + + override fun request(): Request = delegate.request() + override fun timeout(): Timeout = delegate.timeout() + + companion object { + private const val ERROR_UNSUPPORTED_EXCEPTION = "EdonymyeonCall doesn't support" + private const val ERROR_BODY_NOT_EXIST = + "Body doesn't exist, must be declared ApiResponse" + private const val ERROR_AUTHORIZATION_CODE = 1523 + } +} diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/EdonymyeonCallAdapter.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/EdonymyeonCallAdapter.kt new file mode 100644 index 000000000..778d0c14d --- /dev/null +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/EdonymyeonCallAdapter.kt @@ -0,0 +1,14 @@ +package com.app.edonymyeon.data.service.client.calladapter + +import retrofit2.Call +import retrofit2.CallAdapter +import java.lang.reflect.Type + +class EdonymyeonCallAdapter(private val responseType: Type) : + CallAdapter> { + override fun responseType(): Type = responseType + + override fun adapt(call: Call): EdonymyeonCall { + return EdonymyeonCall(call, responseType) + } +} diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/EdonymyeonCallAdapterFactory.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/EdonymyeonCallAdapterFactory.kt new file mode 100644 index 000000000..8629186ee --- /dev/null +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/EdonymyeonCallAdapterFactory.kt @@ -0,0 +1,34 @@ +package com.app.edonymyeon.data.service.client.calladapter + +import retrofit2.Call +import retrofit2.CallAdapter +import retrofit2.Retrofit +import java.lang.reflect.ParameterizedType +import java.lang.reflect.Type + +class EdonymyeonCallAdapterFactory : CallAdapter.Factory() { + override fun get( + returnType: Type, + annotations: Array, + retrofit: Retrofit, + ): CallAdapter<*, *>? { + if (getRawType(returnType) != Call::class.java) return null + check(returnType is ParameterizedType) { + ERROR_NOT_MATCH_GENERIC_TYPE + } + + val wrapperType = getParameterUpperBound(0, returnType) + if (getRawType(wrapperType) != ApiResponse::class.java) return null + check(wrapperType is ParameterizedType) { + ERROR_NOT_MATCH_GENERIC_TYPE + } + + val bodyType = getParameterUpperBound(0, wrapperType) + return EdonymyeonCallAdapter(bodyType) + } + + companion object { + private const val ERROR_NOT_MATCH_GENERIC_TYPE = + "Call return type must be parameterized as Call or Call" + } +} diff --git a/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/ErrorResponse.kt b/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/ErrorResponse.kt new file mode 100644 index 000000000..2997491df --- /dev/null +++ b/android/app/src/main/java/com/app/edonymyeon/data/service/client/calladapter/ErrorResponse.kt @@ -0,0 +1,10 @@ +package com.app.edonymyeon.data.service.client.calladapter + +import com.google.gson.annotations.SerializedName +import kotlinx.serialization.Serializable + +@Serializable +data class ErrorResponse( + @SerializedName("errorCode") val errorCode: Int, + @SerializedName("errorMessage") val errorMessage: String, +) diff --git a/android/app/src/main/java/com/app/edonymyeon/di/RetrofitModule.kt b/android/app/src/main/java/com/app/edonymyeon/di/RetrofitModule.kt index 7ff502253..10deebec8 100644 --- a/android/app/src/main/java/com/app/edonymyeon/di/RetrofitModule.kt +++ b/android/app/src/main/java/com/app/edonymyeon/di/RetrofitModule.kt @@ -2,6 +2,7 @@ package com.app.edonymyeon.di import app.edonymyeon.BuildConfig import com.app.edonymyeon.data.service.client.AccessTokenInterceptor +import com.app.edonymyeon.data.service.client.calladapter.EdonymyeonCallAdapterFactory import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory import dagger.Module import dagger.Provides @@ -25,6 +26,7 @@ object RetrofitModule { fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit { return Retrofit.Builder() .baseUrl(BASE_URL) + .addCallAdapterFactory(EdonymyeonCallAdapterFactory()) .addConverterFactory(Json.asConverterFactory(CONTENT_TYPE)) .client(okHttpClient) .build() diff --git a/android/app/src/main/java/com/app/edonymyeon/mapper/ApiResponseMapper.kt b/android/app/src/main/java/com/app/edonymyeon/mapper/ApiResponseMapper.kt new file mode 100644 index 000000000..ebf4003e6 --- /dev/null +++ b/android/app/src/main/java/com/app/edonymyeon/mapper/ApiResponseMapper.kt @@ -0,0 +1,34 @@ +package com.app.edonymyeon.mapper + +import com.app.edonymyeon.presentation.common.exception.HttpException +import com.app.edonymyeon.data.service.client.calladapter.ApiResponse +import okhttp3.Headers + +fun ApiResponse.toResult( + handleSuccess: ((T, Headers) -> R)? = null, +): Result { + return when (this) { + is ApiResponse.Success -> { + val resultData: R = handleSuccess?.invoke(data, headers) ?: data as R + Result.success(resultData) + } + + is ApiResponse.Failure -> { + val exception = when (this) { + is ApiResponse.Failure.NoAuthError -> HttpException.NoAuthException( + errorResponse.errorCode, + errorResponse.errorMessage, + ) + + is ApiResponse.Failure.HttpError -> HttpException.HttpError( + errorResponse.errorCode, + errorResponse.errorMessage, + ) + + is ApiResponse.Failure.UnknownApiError -> HttpException.UnknownApiError(throwable) + is ApiResponse.Failure.NetworkError -> HttpException.NetworkError(throwable) + } + Result.failure(exception) + } + } +} diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/common/activity/BaseActivity.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/common/activity/BaseActivity.kt index f227d14ab..c3487933c 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/common/activity/BaseActivity.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/common/activity/BaseActivity.kt @@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.databinding.ViewDataBinding import app.edonymyeon.R import com.app.edonymyeon.data.common.FetchState +import com.app.edonymyeon.presentation.common.exception.HttpException import com.app.edonymyeon.presentation.common.viewmodel.BaseViewModel import com.app.edonymyeon.presentation.ui.login.LoginActivity import com.app.edonymyeon.presentation.util.makeSnackbar @@ -29,13 +30,13 @@ abstract class BaseActivity(private val is FetchState.NoAuthorization -> { viewModel.clearAuthToken() binding.root.makeSnackbarWithEvent( - message = it.customThrowable.message, + message = (it.customThrowable as HttpException.NoAuthException).errorMessage, eventTitle = getString(R.string.login_title), ) { navigateToLogin() } } is FetchState.Fail -> { - binding.root.makeSnackbar(it.customThrowable.message) + binding.root.makeSnackbar((it.customThrowable as HttpException.HttpError).errorMessage) } } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/common/exception/HttpException.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/common/exception/HttpException.kt new file mode 100644 index 000000000..4029a97a9 --- /dev/null +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/common/exception/HttpException.kt @@ -0,0 +1,8 @@ +package com.app.edonymyeon.presentation.common.exception + +sealed class HttpException : Exception() { + data class NoAuthException(val errorCode: Int, val errorMessage: String) : HttpException() + data class HttpError(val errorCode: Int, val errorMessage: String) : HttpException() + data class UnknownApiError(val throwable: Throwable) : HttpException() + data class NetworkError(val throwable: Throwable) : HttpException() +} diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/common/fragment/BaseFragment.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/common/fragment/BaseFragment.kt index 282100636..cc4a9b89d 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/common/fragment/BaseFragment.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/common/fragment/BaseFragment.kt @@ -6,6 +6,7 @@ import androidx.databinding.ViewDataBinding import androidx.fragment.app.Fragment import app.edonymyeon.R import com.app.edonymyeon.data.common.FetchState +import com.app.edonymyeon.presentation.common.exception.HttpException import com.app.edonymyeon.presentation.common.viewmodel.BaseViewModel import com.app.edonymyeon.presentation.ui.login.LoginActivity import com.app.edonymyeon.presentation.util.makeSnackbar @@ -29,13 +30,13 @@ abstract class BaseFragment(private val is FetchState.NoAuthorization -> { viewModel.clearAuthToken() binding.root.makeSnackbarWithEvent( - message = it.customThrowable.message, + message = (it.customThrowable as HttpException.NoAuthException).errorMessage, eventTitle = getString(R.string.login_title), ) { navigateToLogin() } } is FetchState.Fail -> { - binding.root.makeSnackbar(it.customThrowable.message) + binding.root.makeSnackbar((it.customThrowable as HttpException.HttpError).errorMessage) } } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/common/viewmodel/BaseViewModel.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/common/viewmodel/BaseViewModel.kt index ac3e8d096..7578ed921 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/common/viewmodel/BaseViewModel.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/common/viewmodel/BaseViewModel.kt @@ -3,16 +3,12 @@ package com.app.edonymyeon.presentation.common.viewmodel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import com.app.edonymyeon.data.common.CustomThrowable import com.app.edonymyeon.data.common.FetchState -import com.bumptech.glide.load.HttpException +import com.app.edonymyeon.presentation.common.exception.HttpException import com.domain.edonymyeon.repository.AuthRepository import kotlinx.coroutines.CoroutineExceptionHandler -import java.net.SocketException -import java.net.UnknownHostException -import javax.inject.Inject -open class BaseViewModel @Inject constructor(val authRepository: AuthRepository) : ViewModel() { +open class BaseViewModel(val authRepository: AuthRepository) : ViewModel() { private val _fetchState = MutableLiveData() val fetchState: LiveData @@ -20,17 +16,13 @@ open class BaseViewModel @Inject constructor(val authRepository: AuthRepository) protected val exceptionHandler = CoroutineExceptionHandler { _, throwable -> throwable.printStackTrace() + if (throwable is HttpException) { + when (throwable) { + is HttpException.NoAuthException -> + FetchState.NoAuthorization(throwable) - when (throwable) { - is SocketException -> _fetchState.value = FetchState.BadInternet - is HttpException -> _fetchState.value = FetchState.ParseError - is UnknownHostException -> _fetchState.value = FetchState.WrongConnection - else -> { - if ((throwable as CustomThrowable).code == NO_AUTHORIZATION_CODE) { - _fetchState.value = FetchState.NoAuthorization(throwable) - } else { - _fetchState.value = FetchState.Fail(throwable) - } + is HttpException.HttpError -> _fetchState.value = FetchState.Fail(throwable) + else -> FetchState.BadInternet } } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/alarmsetting/AlarmSettingViewModel.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/alarmsetting/AlarmSettingViewModel.kt index 52337395c..e5a456a9c 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/alarmsetting/AlarmSettingViewModel.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/alarmsetting/AlarmSettingViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.app.edonymyeon.presentation.common.viewmodel.BaseViewModel +import com.app.edonymyeon.presentation.util.onFailureWithApiException import com.domain.edonymyeon.model.NotificationPreference import com.domain.edonymyeon.repository.AuthRepository import com.domain.edonymyeon.repository.PreferenceRepository @@ -88,7 +89,7 @@ class AlarmSettingViewModel @Inject constructor( response.map { setNotificationSetting(it) } - }.onFailure { + }.onFailureWithApiException { throw it } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/login/LoginViewModel.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/login/LoginViewModel.kt index 7276b4fda..b52f570b1 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/login/LoginViewModel.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/login/LoginViewModel.kt @@ -3,9 +3,9 @@ package com.app.edonymyeon.presentation.ui.login import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import com.app.edonymyeon.data.common.CustomThrowable import com.app.edonymyeon.data.service.fcm.FCMToken import com.app.edonymyeon.presentation.common.viewmodel.BaseViewModel +import com.app.edonymyeon.presentation.util.onFailureWithApiException import com.domain.edonymyeon.repository.AuthRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch @@ -41,7 +41,7 @@ class LoginViewModel @Inject constructor( it ?: "", ).onSuccess { _isSuccess.value = true - }.onFailure { + }.onFailureWithApiException { _isSuccess.value = false throw it } @@ -57,9 +57,8 @@ class LoginViewModel @Inject constructor( it.orEmpty(), ).onSuccess { _isSuccess.value = true - }.onFailure { + }.onFailureWithApiException { _isSuccess.value = false - _errorMessage.postValue((it as CustomThrowable).message) throw it } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/alarm/AlarmViewModel.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/alarm/AlarmViewModel.kt index b13facc73..bfa865b4b 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/alarm/AlarmViewModel.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/alarm/AlarmViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope import com.app.edonymyeon.mapper.toUiModel import com.app.edonymyeon.presentation.common.viewmodel.BaseViewModel import com.app.edonymyeon.presentation.uimodel.NotificationUiModel +import com.app.edonymyeon.presentation.util.onFailureWithApiException import com.domain.edonymyeon.model.Page import com.domain.edonymyeon.repository.AuthRepository import com.domain.edonymyeon.repository.NotificationRepository @@ -37,13 +38,13 @@ class AlarmViewModel @Inject constructor( if (result.isSuccess) { _notificationList.value = notificationList.value.orEmpty() + - result.getOrNull()?.notifications?.map { - it.toUiModel() - }.orEmpty() + result.getOrNull()?.notifications?.map { + it.toUiModel() + }.orEmpty() currentPage = currentPage.increasePage() isLastPage = result.getOrNull()?.isLast ?: true } else { - result.onFailure { throw it } + result.onFailureWithApiException { throw it } } } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/home/HomeViewModel.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/home/HomeViewModel.kt index 240100c13..a19dbb131 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/home/HomeViewModel.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/home/HomeViewModel.kt @@ -8,6 +8,7 @@ import com.app.edonymyeon.mapper.toUiModel import com.app.edonymyeon.presentation.common.viewmodel.BaseViewModel import com.app.edonymyeon.presentation.uimodel.AllPostItemUiModel import com.app.edonymyeon.presentation.uimodel.PostItemUiModel +import com.app.edonymyeon.presentation.util.onFailureWithApiException import com.domain.edonymyeon.repository.AuthRepository import com.domain.edonymyeon.repository.PostRepository import dagger.hilt.android.lifecycle.HiltViewModel @@ -38,7 +39,7 @@ class HomeViewModel @Inject constructor( post.toAllPostItemUiModel() } _allPostsSuccess.value = true - }.onFailure { + }.onFailureWithApiException { _allPostsSuccess.value = false throw it } @@ -49,7 +50,7 @@ class HomeViewModel @Inject constructor( viewModelScope.launch(exceptionHandler) { postRepository.getHotPosts().onSuccess { post -> _hotPosts.value = post.posts.map { it.toUiModel() } - }.onFailure { + }.onFailureWithApiException { throw it } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/mypage/MyPageViewModel.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/mypage/MyPageViewModel.kt index 287d2e34d..105ded7f8 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/mypage/MyPageViewModel.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/mypage/MyPageViewModel.kt @@ -11,6 +11,7 @@ import com.app.edonymyeon.presentation.uimodel.ConsumptionAmountUiModel import com.app.edonymyeon.presentation.uimodel.ConsumptionStatisticsUiModel import com.app.edonymyeon.presentation.uimodel.NicknameUiModel import com.app.edonymyeon.presentation.uimodel.WriterUiModel +import com.app.edonymyeon.presentation.util.onFailureWithApiException import com.domain.edonymyeon.model.ConsumptionStatistics import com.domain.edonymyeon.repository.AuthRepository import com.domain.edonymyeon.repository.ConsumptionsRepository @@ -51,7 +52,7 @@ class MyPageViewModel @Inject constructor( viewModelScope.launch(exceptionHandler) { profileRepository.getProfile().onSuccess { _profile.value = it.toUiModel() - }.onFailure { + }.onFailureWithApiException { throw it } } @@ -68,7 +69,7 @@ class MyPageViewModel @Inject constructor( it as ConsumptionStatistics _consumptions.value = it.toUiModel() _consumptionOnThisMonth.value = it.consumptionAmounts.last().toUiModel() - }.onFailure { + }.onFailureWithApiException { throw it } } @@ -79,7 +80,7 @@ class MyPageViewModel @Inject constructor( viewModelScope.launch(exceptionHandler) { authRepository.logout(it ?: "").onSuccess { _isLogoutSuccess.value = true - }.onFailure { + }.onFailureWithApiException { throw it } } @@ -89,7 +90,7 @@ class MyPageViewModel @Inject constructor( fun withdraw() { viewModelScope.launch(exceptionHandler) { profileRepository.withdraw() - .onFailure { + .onFailureWithApiException { throw it } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/search/SearchViewModel.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/search/SearchViewModel.kt index 3e29ca92d..8673a39fa 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/search/SearchViewModel.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/main/search/SearchViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope import com.app.edonymyeon.mapper.toUiModel import com.app.edonymyeon.presentation.common.viewmodel.BaseViewModel import com.app.edonymyeon.presentation.uimodel.PostItemUiModel +import com.app.edonymyeon.presentation.util.onFailureWithApiException import com.domain.edonymyeon.model.Page import com.domain.edonymyeon.repository.AuthRepository import com.domain.edonymyeon.repository.SearchRepository @@ -34,7 +35,7 @@ class SearchViewModel @Inject constructor( currentPage = currentPage.increasePage() isLastPage = result.isLast } - .onFailure { + .onFailureWithApiException { throw it } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/mypost/MyPostViewModel.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/mypost/MyPostViewModel.kt index b64594f5e..75634d9c7 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/mypost/MyPostViewModel.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/mypost/MyPostViewModel.kt @@ -7,6 +7,7 @@ import com.app.edonymyeon.mapper.toUiModel import com.app.edonymyeon.presentation.common.viewmodel.BaseViewModel import com.app.edonymyeon.presentation.uimodel.ConsumptionUiModel import com.app.edonymyeon.presentation.uimodel.MyPostUiModel +import com.app.edonymyeon.presentation.util.onFailureWithApiException import com.domain.edonymyeon.model.Date import com.domain.edonymyeon.model.MonthRange import com.domain.edonymyeon.model.Page @@ -50,10 +51,9 @@ class MyPostViewModel @Inject constructor( } currentPage = currentPage.increasePage() isLastPage = it.isLast + }.onFailureWithApiException { + throw it } - .onFailure { - throw it - } } } @@ -78,7 +78,7 @@ class MyPostViewModel @Inject constructor( ) viewModelScope.launch(exceptionHandler) { profileRepository.postPurchaseConfirm(id, purchasePrice, year, month).onSuccess { - }.onFailure { + }.onFailureWithApiException { throw it } } @@ -92,7 +92,7 @@ class MyPostViewModel @Inject constructor( viewModelScope.launch(exceptionHandler) { profileRepository.postSavingConfirm(id, year, month).onSuccess { } - .onFailure { + .onFailureWithApiException { throw it } } @@ -106,7 +106,7 @@ class MyPostViewModel @Inject constructor( viewModelScope.launch(exceptionHandler) { profileRepository.deleteConfirm(id).onSuccess { } - .onFailure { + .onFailureWithApiException { throw it } } @@ -144,7 +144,7 @@ class MyPostViewModel @Inject constructor( viewModelScope.launch(exceptionHandler) { postRepository.getPostDetail(id).onSuccess { _price.value = (it as Post).price.toString() - }.onFailure { + }.onFailureWithApiException { throw it } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/mypost/dialog/ConsumptionDialog.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/mypost/dialog/ConsumptionDialog.kt index 517aae69b..afa59fd3f 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/mypost/dialog/ConsumptionDialog.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/mypost/dialog/ConsumptionDialog.kt @@ -12,6 +12,7 @@ import app.edonymyeon.databinding.DialogInputConsumptionBinding import com.app.edonymyeon.presentation.ui.mypost.ConsumptionType import com.app.edonymyeon.presentation.ui.mypost.MyPostViewModel import com.app.edonymyeon.presentation.util.makeSnackbar +import com.app.edonymyeon.presentation.util.onFailureWithApiException class ConsumptionDialog( private val type: ConsumptionType, @@ -48,7 +49,7 @@ class ConsumptionDialog( private fun setObserver() { viewModel.price.observe(this) { price -> - runCatching { if (price != BLANK) price?.toInt() ?: 0 }.onFailure { + runCatching { if (price != BLANK) price?.toInt() ?: 0 }.onFailureWithApiException { binding.root.makeSnackbar(this.getString(R.string.dialog_input_price_error_message)) viewModel.setPurchasePrice(BLANK) } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/post/PostViewModel.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/post/PostViewModel.kt index 67ae30b6a..db3e8e0fb 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/post/PostViewModel.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/post/PostViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope import com.app.edonymyeon.mapper.toUiModel import com.app.edonymyeon.presentation.common.viewmodel.BaseViewModel import com.app.edonymyeon.presentation.uimodel.PostItemUiModel +import com.app.edonymyeon.presentation.util.onFailureWithApiException import com.domain.edonymyeon.model.Page import com.domain.edonymyeon.repository.AuthRepository import com.domain.edonymyeon.repository.PostRepository @@ -38,10 +39,9 @@ class PostViewModel @Inject constructor( } currentPage = currentPage.increasePage() isLastPage = result.isLast + }.onFailureWithApiException { + throw it } - .onFailure { - throw it - } } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/postdetail/PostDetailViewModel.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/postdetail/PostDetailViewModel.kt index d03e24489..c37923b6c 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/postdetail/PostDetailViewModel.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/postdetail/PostDetailViewModel.kt @@ -14,6 +14,7 @@ import com.app.edonymyeon.presentation.uimodel.CommentUiModel import com.app.edonymyeon.presentation.uimodel.PostUiModel import com.app.edonymyeon.presentation.uimodel.ReactionCountUiModel import com.app.edonymyeon.presentation.uimodel.RecommendationUiModel +import com.app.edonymyeon.presentation.util.onFailureWithApiException import com.domain.edonymyeon.model.Post import com.domain.edonymyeon.model.Recommendation import com.domain.edonymyeon.repository.AuthRepository @@ -95,7 +96,7 @@ class PostDetailViewModel @Inject constructor( _post.value = it.toUiModel() _isPostLoadingSuccess.value = true checkLoadingSuccess() - }.onFailure { + }.onFailureWithApiException { val customThrowable = it as CustomThrowable when (customThrowable.code) { 2000 -> { @@ -114,7 +115,7 @@ class PostDetailViewModel @Inject constructor( viewModelScope.launch(exceptionHandler) { postRepository.deletePost(postId) .onSuccess {} - .onFailure { + .onFailureWithApiException { throw it } } @@ -127,7 +128,7 @@ class PostDetailViewModel @Inject constructor( .onSuccess { _reportSaveMessage.value = MESSAGE_REPORT_SUCCESS } - .onFailure { + .onFailureWithApiException { throw it } } @@ -221,7 +222,7 @@ class PostDetailViewModel @Inject constructor( .onSuccess { _isRecommendationRequestDone.value = true } - .onFailure { + .onFailureWithApiException { _isRecommendationRequestDone.value = true throw it } @@ -237,7 +238,7 @@ class PostDetailViewModel @Inject constructor( ) ?: ReactionCountUiModel(0, comments.commentCount) _isCommentsLoadingSuccess.value = true checkLoadingSuccess() - }.onFailure { + }.onFailureWithApiException { _isCommentsLoadingSuccess.value = false throw it } @@ -253,7 +254,7 @@ class PostDetailViewModel @Inject constructor( ).onSuccess { getComments(postId) _isCommentSaveSuccess.value = true - }.onFailure { + }.onFailureWithApiException { _isCommentSaveSuccess.value = false throw it } @@ -267,7 +268,7 @@ class PostDetailViewModel @Inject constructor( commentId, ).onSuccess { getComments(postId) - }.onFailure { + }.onFailureWithApiException { throw it } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/posteditor/PostEditorViewModel.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/posteditor/PostEditorViewModel.kt index cc8f00c81..21fa7d706 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/posteditor/PostEditorViewModel.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/posteditor/PostEditorViewModel.kt @@ -12,6 +12,7 @@ import com.app.edonymyeon.presentation.common.viewmodel.BaseViewModel import com.app.edonymyeon.presentation.ui.mypost.dialog.ConsumptionDialog import com.app.edonymyeon.presentation.uimodel.PostEditorUiModel import com.app.edonymyeon.presentation.uimodel.PostUiModel +import com.app.edonymyeon.presentation.util.onFailureWithApiException import com.domain.edonymyeon.model.PostEditor import com.domain.edonymyeon.repository.AuthRepository import com.domain.edonymyeon.repository.PostRepository @@ -57,7 +58,7 @@ class PostEditorViewModel @Inject constructor( ), ).onSuccess { _postId.value = (it as PostEditorResponse).id - }.onFailure { + }.onFailureWithApiException { throw it } } @@ -73,7 +74,7 @@ class PostEditorViewModel @Inject constructor( getFileFromContent(context, uris), ).onSuccess { _postId.value = (it as PostEditorResponse).id - }.onFailure { + }.onFailureWithApiException { throw it } } @@ -97,7 +98,7 @@ class PostEditorViewModel @Inject constructor( } }.onSuccess { _isPostPriceValid.value = true - }.onFailure { + }.onFailureWithApiException { _isPostPriceValid.value = false } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/profileupdate/ProfileUpdateViewModel.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/profileupdate/ProfileUpdateViewModel.kt index 323c577f4..a0fef84a0 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/profileupdate/ProfileUpdateViewModel.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/profileupdate/ProfileUpdateViewModel.kt @@ -8,6 +8,7 @@ import androidx.lifecycle.viewModelScope import com.app.edonymyeon.presentation.common.imageutil.processAndAdjustImage import com.app.edonymyeon.presentation.common.viewmodel.BaseViewModel import com.app.edonymyeon.presentation.uimodel.WriterUiModel +import com.app.edonymyeon.presentation.util.onFailureWithApiException import com.domain.edonymyeon.model.Nickname import com.domain.edonymyeon.repository.AuthRepository import com.domain.edonymyeon.repository.ProfileRepository @@ -82,7 +83,7 @@ class ProfileUpdateViewModel @Inject constructor( .onSuccess { _isNicknameValid.value = it && Nickname.validate(newNickname) checkAbleToUpdate() - }.onFailure { + }.onFailureWithApiException { _isNicknameValid.value = false throw it } @@ -115,7 +116,7 @@ class ProfileUpdateViewModel @Inject constructor( isImageChanged, ).onSuccess { _isUploadSuccess.value = true - }.onFailure { + }.onFailureWithApiException { throw it } } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/signup/SignUpViewModel.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/signup/SignUpViewModel.kt index 1a269594a..070dc4963 100644 --- a/android/app/src/main/java/com/app/edonymyeon/presentation/ui/signup/SignUpViewModel.kt +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/ui/signup/SignUpViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.app.edonymyeon.data.service.fcm.FCMToken import com.app.edonymyeon.presentation.common.viewmodel.BaseViewModel +import com.app.edonymyeon.presentation.util.onFailureWithApiException import com.domain.edonymyeon.model.Email import com.domain.edonymyeon.model.Nickname import com.domain.edonymyeon.model.Password @@ -48,7 +49,7 @@ class SignUpViewModel @Inject constructor( ), ).onSuccess { _isSignUpSuccess.value = true - }.onFailure { + }.onFailureWithApiException { _isSignUpSuccess.value = false throw it } @@ -83,16 +84,16 @@ class SignUpViewModel @Inject constructor( private fun checkSignUpAble() { _isSignUpAble.value = isEmailValid.value ?: false && - isNicknameValid.value ?: false && - isPasswordValid.value ?: false && - isPasswordCheckValid.value ?: false + isNicknameValid.value ?: false && + isPasswordValid.value ?: false && + isPasswordCheckValid.value ?: false } fun verifyEmail(email: String) { viewModelScope.launch(exceptionHandler) { authRepository.checkDuplicate(EMAIL, email.trim()).onSuccess { _isEmailValid.value = it && Email.validate(email) - }.onFailure { + }.onFailureWithApiException { _isEmailValid.value = false throw it } @@ -103,7 +104,7 @@ class SignUpViewModel @Inject constructor( viewModelScope.launch(exceptionHandler) { authRepository.checkDuplicate(NICKNAME, nickname.trim()).onSuccess { _isNicknameValid.value = it && Nickname.validate(nickname) - }.onFailure { + }.onFailureWithApiException { _isNicknameValid.value = false throw it } diff --git a/android/app/src/main/java/com/app/edonymyeon/presentation/util/ResultUtil.kt b/android/app/src/main/java/com/app/edonymyeon/presentation/util/ResultUtil.kt new file mode 100644 index 000000000..959dfe564 --- /dev/null +++ b/android/app/src/main/java/com/app/edonymyeon/presentation/util/ResultUtil.kt @@ -0,0 +1,9 @@ +package com.app.edonymyeon.presentation.util + +import com.app.edonymyeon.presentation.common.exception.HttpException + +fun Result.onFailureWithApiException(onAction: (HttpException) -> Unit) { + onFailure { + onAction(it as HttpException) + } +}