diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 716e102d..57a73b72 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -21,7 +21,7 @@ android { applicationId = "com.eatssu.android" minSdk = 23 targetSdk = 34 - versionCode = 21 + versionCode = 22 versionName = "2.1.1" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/com/eatssu/android/App.kt b/app/src/main/java/com/eatssu/android/App.kt index af142e29..dba3085c 100644 --- a/app/src/main/java/com/eatssu/android/App.kt +++ b/app/src/main/java/com/eatssu/android/App.kt @@ -20,6 +20,8 @@ class App: Application() { appContext = this KakaoSdk.init(this,BuildConfig.KAKAO_NATIVE_APP_KEY) - Timber.plant(Timber.DebugTree()) + if (BuildConfig.DEBUG) { + Timber.plant(Timber.DebugTree()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/dto/response/MenuOfMealResponse.kt b/app/src/main/java/com/eatssu/android/data/dto/response/MenuOfMealResponse.kt index b38fe71c..831d3752 100644 --- a/app/src/main/java/com/eatssu/android/data/dto/response/MenuOfMealResponse.kt +++ b/app/src/main/java/com/eatssu/android/data/dto/response/MenuOfMealResponse.kt @@ -14,14 +14,13 @@ data class MenusInformation( ) -fun MenuOfMealResponse.asMenuOfMeal(): List { - val menuList = mutableListOf() - - this.menusInformation.forEach { - - val menu = MenuMini(it.menuId, it.name) - menuList.add(menu) - } - - return menuList +fun MenuOfMealResponse.toMenuMiniList(): List { + return menusInformation.map { it.toMenuMini() } +} + +fun MenusInformation.toMenuMini(): MenuMini { + return MenuMini( + id = this.menuId, + name = this.name + ) } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/repository/ImageRepository.kt b/app/src/main/java/com/eatssu/android/data/repository/ImageRepository.kt deleted file mode 100644 index 87cefe0b..00000000 --- a/app/src/main/java/com/eatssu/android/data/repository/ImageRepository.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.eatssu.android.data.repository - - -interface ImageRepository { - -// suspend fun getImageString( -// image: MultipartBody.Part -// ): Flow - -// suspend fun login(idToken: String): Flow -} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/repository/ImageRepositoryImpl.kt b/app/src/main/java/com/eatssu/android/data/repository/ImageRepositoryImpl.kt deleted file mode 100644 index b01a0423..00000000 --- a/app/src/main/java/com/eatssu/android/data/repository/ImageRepositoryImpl.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.eatssu.android.data.repository - -import com.eatssu.android.data.service.ImageService -import javax.inject.Inject - -class ImageRepositoryImpl @Inject constructor(private val imageService: ImageService) : - ImageRepository { - - -// override suspend fun getImageString( -// image: MultipartBody.Part -// ): Flow = flow { -// emit(imageService.getImageUrl(image)) -// } - - -} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/repository/MealRepository.kt b/app/src/main/java/com/eatssu/android/data/repository/MealRepository.kt new file mode 100644 index 00000000..c2c55e43 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/data/repository/MealRepository.kt @@ -0,0 +1,17 @@ +package com.eatssu.android.data.repository + +import com.eatssu.android.base.BaseResponse +import com.eatssu.android.data.dto.response.MenuOfMealResponse +import kotlinx.coroutines.flow.Flow + +interface MealRepository { +// suspend fun getTodayMeal( +// date: String, +// restaurant: String, +// time: String, +// ): Flow>> + + suspend fun getMenuInfoByMealId( + mealId: Long, + ): Flow> +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/repository/MealRepositoryImpl.kt b/app/src/main/java/com/eatssu/android/data/repository/MealRepositoryImpl.kt new file mode 100644 index 00000000..8edf32fa --- /dev/null +++ b/app/src/main/java/com/eatssu/android/data/repository/MealRepositoryImpl.kt @@ -0,0 +1,24 @@ +package com.eatssu.android.data.repository + +import com.eatssu.android.base.BaseResponse +import com.eatssu.android.data.dto.response.MenuOfMealResponse +import com.eatssu.android.data.service.MealService +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class MealRepositoryImpl @Inject constructor(private val mealService: MealService) : + MealRepository { + +// override suspend fun getTodayMeal( +// date: String, +// restaurant: String, +// time: String +// ): Flow>> = +// flow { emit(mealService.getTodayMeal(date, restaurant, time)) } + + override suspend fun getMenuInfoByMealId(mealId: Long): Flow> = + flow { + emit(mealService.getMenuInfoByMealId(mealId)) + } +} diff --git a/app/src/main/java/com/eatssu/android/data/repository/ReviewRepository.kt b/app/src/main/java/com/eatssu/android/data/repository/ReviewRepository.kt index 2af1eca7..85cdbbd5 100644 --- a/app/src/main/java/com/eatssu/android/data/repository/ReviewRepository.kt +++ b/app/src/main/java/com/eatssu/android/data/repository/ReviewRepository.kt @@ -1,19 +1,47 @@ package com.eatssu.android.data.repository -import com.eatssu.android.data.service.ReviewService +import com.eatssu.android.base.BaseResponse +import com.eatssu.android.data.dto.request.ModifyReviewRequest +import com.eatssu.android.data.dto.request.WriteReviewRequest +import com.eatssu.android.data.dto.response.GetMealReviewInfoResponse +import com.eatssu.android.data.dto.response.GetMenuReviewInfoResponse +import com.eatssu.android.data.dto.response.GetReviewListResponse +import com.eatssu.android.data.dto.response.ImageResponse +import kotlinx.coroutines.flow.Flow +import okhttp3.MultipartBody -class ReviewRepository(private val reviewService: ReviewService) { +interface ReviewRepository { -// override suspend fun reissueToken( -// refreshToken: String -// ): Flow = flow { -// emit(authService.reissueToken(refreshToken)) -// } + suspend fun writeReview( + menuId: Long, + body: WriteReviewRequest, + ): Flow> -// suspend fun getMenuReviewInfo(menuId: Long) -// : Flow> = -// flow { -// emit(reviewService.getMenuReviewInfo(menuId)) -// } + suspend fun deleteReview( + reviewId: Long, + ): Flow> + suspend fun modifyReview( + reviewId: Long, + body: ModifyReviewRequest, + ): Flow> + + suspend fun getReviewList( + menuType: String, + mealId: Long?, + menuId: Long?, + ): Flow> + + suspend fun getMenuReviewInfo( + menuId: Long, + ): Flow> + + + suspend fun getMealReviewInfo( + mealId: Long, + ): Flow> + + suspend fun getImageString( + image: MultipartBody.Part, + ): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/repository/ReviewRepositoryImpl.kt b/app/src/main/java/com/eatssu/android/data/repository/ReviewRepositoryImpl.kt new file mode 100644 index 00000000..5cd6b793 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/data/repository/ReviewRepositoryImpl.kt @@ -0,0 +1,65 @@ +package com.eatssu.android.data.repository + +import com.eatssu.android.base.BaseResponse +import com.eatssu.android.data.dto.request.ModifyReviewRequest +import com.eatssu.android.data.dto.request.WriteReviewRequest +import com.eatssu.android.data.dto.response.GetMealReviewInfoResponse +import com.eatssu.android.data.dto.response.GetMenuReviewInfoResponse +import com.eatssu.android.data.dto.response.GetReviewListResponse +import com.eatssu.android.data.dto.response.ImageResponse +import com.eatssu.android.data.service.ReviewService +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import okhttp3.MultipartBody +import javax.inject.Inject + +class ReviewRepositoryImpl @Inject constructor(private val reviewService: ReviewService) : + ReviewRepository { + + override suspend fun writeReview( + menuId: Long, + body: WriteReviewRequest, + ): Flow> = + flow { + emit(reviewService.writeReview(menuId, body)) + } + + override suspend fun deleteReview(reviewId: Long): Flow> = + flow { + emit(reviewService.deleteReview(reviewId)) + } + + override suspend fun modifyReview( + reviewId: Long, + body: ModifyReviewRequest, + ): Flow> = + flow { + emit(reviewService.modifyReview(reviewId, body)) + } + + override suspend fun getReviewList( + menuType: String, + mealId: Long?, + menuId: Long?, + ): Flow> = flow { + emit(reviewService.getReviewList(menuType, mealId, menuId)) + } + + override suspend fun getMenuReviewInfo(menuId: Long): Flow> = + flow { + emit(reviewService.getMenuReviewInfo(menuId)) + } + + override suspend fun getMealReviewInfo(mealId: Long): Flow> = + flow { + emit(reviewService.getMealReviewInfo(mealId)) + } + + override suspend fun getImageString( + image: MultipartBody.Part, + ): Flow> = + flow { + emit(reviewService.uploadImage(image)) + } + +} diff --git a/app/src/main/java/com/eatssu/android/data/service/ImageService.kt b/app/src/main/java/com/eatssu/android/data/service/ImageService.kt deleted file mode 100644 index 5f821b65..00000000 --- a/app/src/main/java/com/eatssu/android/data/service/ImageService.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.eatssu.android.data.service - -import com.eatssu.android.base.BaseResponse -import com.eatssu.android.data.dto.response.ImageResponse -import okhttp3.MultipartBody -import retrofit2.Call -import retrofit2.http.Multipart -import retrofit2.http.POST -import retrofit2.http.Part - -interface ImageService { - - @Multipart - @POST("/reviews/upload/image") //리뷰 이미지 업로드 - fun getImageUrl( - @Part image: MultipartBody.Part, - ): Call> -} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/service/MealService.kt b/app/src/main/java/com/eatssu/android/data/service/MealService.kt index b1997533..79b0b3a7 100644 --- a/app/src/main/java/com/eatssu/android/data/service/MealService.kt +++ b/app/src/main/java/com/eatssu/android/data/service/MealService.kt @@ -17,8 +17,8 @@ interface MealService { ): Call>> @GET("meals/{mealId}/menus-info") //메뉴 정보 리스트 조회 - fun getMenuInfoByMealId( + suspend fun getMenuInfoByMealId( @Path("mealId") mealId: Long, - ): Call> + ): BaseResponse } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/service/ReviewService.kt b/app/src/main/java/com/eatssu/android/data/service/ReviewService.kt index dbdd33cd..264aaa2e 100644 --- a/app/src/main/java/com/eatssu/android/data/service/ReviewService.kt +++ b/app/src/main/java/com/eatssu/android/data/service/ReviewService.kt @@ -7,52 +7,63 @@ import com.eatssu.android.data.dto.request.WriteReviewRequest import com.eatssu.android.data.dto.response.GetMealReviewInfoResponse import com.eatssu.android.data.dto.response.GetMenuReviewInfoResponse import com.eatssu.android.data.dto.response.GetReviewListResponse -import retrofit2.Call -import retrofit2.http.* +import com.eatssu.android.data.dto.response.ImageResponse +import okhttp3.MultipartBody +import retrofit2.http.Body +import retrofit2.http.DELETE +import retrofit2.http.GET +import retrofit2.http.Multipart +import retrofit2.http.PATCH +import retrofit2.http.POST +import retrofit2.http.Part +import retrofit2.http.Path +import retrofit2.http.Query interface ReviewService { @POST("/reviews/write/{menuId}") //리뷰 작성 - fun writeReview( + suspend fun writeReview( @Path("menuId") menuId: Long, @Body request: WriteReviewRequest, - ): Call> + ): BaseResponse @DELETE("/reviews/{reviewId}") //리뷰 삭제 - fun deleteReview( + suspend fun deleteReview( @Path("reviewId") reviewId: Long, - ): Call> + ): BaseResponse @PATCH("/reviews/{reviewId}") //리뷰 수정(글 수정) - fun modifyReview( + suspend fun modifyReview( @Path("reviewId") reviewId: Long, @Body request: ModifyReviewRequest, - ): Call> + ): BaseResponse //Todo paging 라이브러리 써보기 @GET("/reviews") //리뷰 리스트 조회 - fun getReviewList( + suspend fun getReviewList( @Query("menuType") menuType: String, @Query("mealId") mealId: Long?, @Query("menuId") menuId: Long?, // @Query("lastReviewId") lastReviewId: Long?, -// @Query("page") page: Int? = -// @Query("size") size: Int? = 20 -// @Query("sort") sort: List? = arrayListOf("date","DESC") - ): Call> - - // @GET("/reviews/menus/{menuId}") //고정 메뉴 리뷰 정보 조회(메뉴명, 평점 등등) -// fun getMenuReviewInfo( -// @Path("menuId") menuId: Long, -// ): BaseResponse + @Query("page") page: Int? = 0, + @Query("size") size: Int? = 20, + @Query("sort") sort: List? = arrayListOf("date", "DESC"), + ): BaseResponse + @GET("/reviews/menus/{menuId}") //고정 메뉴 리뷰 정보 조회(메뉴명, 평점 등등) - fun getMenuReviewInfo( + suspend fun getMenuReviewInfo( @Path("menuId") menuId: Long, - ): Call> + ): BaseResponse @GET("/reviews/meals/{mealId}") //식단(변동 메뉴) 리뷰 정보 조회(메뉴명, 평점 등등) - fun getMealReviewInfo( + suspend fun getMealReviewInfo( @Path("mealId") mealId: Long, - ): Call> + ): BaseResponse + + @Multipart + @POST("/reviews/upload/image") //리뷰 이미지 업로드 + suspend fun uploadImage( + @Part image: MultipartBody.Part, + ): BaseResponse } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/AlarmUsecase.kt b/app/src/main/java/com/eatssu/android/data/usecase/alarm/AlarmUsecase.kt similarity index 97% rename from app/src/main/java/com/eatssu/android/data/usecase/AlarmUsecase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/alarm/AlarmUsecase.kt index 94a65105..2d4794a6 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/AlarmUsecase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/alarm/AlarmUsecase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.alarm import android.app.AlarmManager import android.app.PendingIntent diff --git a/app/src/main/java/com/eatssu/android/data/usecase/GetDailyNotificationStatusUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/alarm/GetDailyNotificationStatusUseCase.kt similarity index 88% rename from app/src/main/java/com/eatssu/android/data/usecase/GetDailyNotificationStatusUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/alarm/GetDailyNotificationStatusUseCase.kt index de4cd4e4..a9a2257a 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/GetDailyNotificationStatusUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/alarm/GetDailyNotificationStatusUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.alarm import com.eatssu.android.data.repository.PreferencesRepository import kotlinx.coroutines.flow.Flow diff --git a/app/src/main/java/com/eatssu/android/data/usecase/SetDailyNotificationStatusUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/alarm/SetDailyNotificationStatusUseCase.kt similarity index 88% rename from app/src/main/java/com/eatssu/android/data/usecase/SetDailyNotificationStatusUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/alarm/SetDailyNotificationStatusUseCase.kt index 4eba7b51..9c3e9dda 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/SetDailyNotificationStatusUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/alarm/SetDailyNotificationStatusUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.alarm import com.eatssu.android.data.repository.PreferencesRepository import javax.inject.Inject diff --git a/app/src/main/java/com/eatssu/android/data/usecase/GetAccessTokenUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/GetAccessTokenUseCase.kt similarity index 89% rename from app/src/main/java/com/eatssu/android/data/usecase/GetAccessTokenUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/GetAccessTokenUseCase.kt index f54de06b..354fa7c3 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/GetAccessTokenUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/GetAccessTokenUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import android.content.Context import com.eatssu.android.util.MySharedPreferences diff --git a/app/src/main/java/com/eatssu/android/data/usecase/GetMyReviewsUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/GetMyReviewsUseCase.kt similarity index 90% rename from app/src/main/java/com/eatssu/android/data/usecase/GetMyReviewsUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/GetMyReviewsUseCase.kt index d5ccd08a..578f9bfd 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/GetMyReviewsUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/GetMyReviewsUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import com.eatssu.android.base.BaseResponse import com.eatssu.android.data.dto.response.MyReviewResponse diff --git a/app/src/main/java/com/eatssu/android/data/usecase/GetRefreshTokenUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/GetRefreshTokenUseCase.kt similarity index 90% rename from app/src/main/java/com/eatssu/android/data/usecase/GetRefreshTokenUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/GetRefreshTokenUseCase.kt index 635780b8..fecc363b 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/GetRefreshTokenUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/GetRefreshTokenUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import android.content.Context import com.eatssu.android.util.MySharedPreferences diff --git a/app/src/main/java/com/eatssu/android/data/usecase/GetUserEmailUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/GetUserEmailUseCase.kt similarity index 89% rename from app/src/main/java/com/eatssu/android/data/usecase/GetUserEmailUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/GetUserEmailUseCase.kt index 5bbabb1c..c24e4b10 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/GetUserEmailUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/GetUserEmailUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import android.content.Context import com.eatssu.android.util.MySharedPreferences diff --git a/app/src/main/java/com/eatssu/android/data/usecase/GetUserInfoUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/GetUserInfoUseCase.kt similarity index 90% rename from app/src/main/java/com/eatssu/android/data/usecase/GetUserInfoUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/GetUserInfoUseCase.kt index 6c9e52d2..45d6fd37 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/GetUserInfoUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/GetUserInfoUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import com.eatssu.android.base.BaseResponse import com.eatssu.android.data.dto.response.MyInfoResponse diff --git a/app/src/main/java/com/eatssu/android/data/usecase/GetUserNameUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/GetUserNameUseCase.kt similarity index 90% rename from app/src/main/java/com/eatssu/android/data/usecase/GetUserNameUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/GetUserNameUseCase.kt index e85a49d9..45dffa63 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/GetUserNameUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/GetUserNameUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import android.content.Context import com.eatssu.android.util.MySharedPreferences diff --git a/app/src/main/java/com/eatssu/android/data/usecase/LoginUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/LoginUseCase.kt similarity index 92% rename from app/src/main/java/com/eatssu/android/data/usecase/LoginUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/LoginUseCase.kt index 0436bce8..8e7fe5ab 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/LoginUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/LoginUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import com.eatssu.android.base.BaseResponse import com.eatssu.android.data.dto.request.LoginWithKakaoRequest diff --git a/app/src/main/java/com/eatssu/android/data/usecase/LogoutUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/LogoutUseCase.kt similarity index 88% rename from app/src/main/java/com/eatssu/android/data/usecase/LogoutUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/LogoutUseCase.kt index 7d1e5b7f..a29b3108 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/LogoutUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/LogoutUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import android.content.Context import com.eatssu.android.util.MySharedPreferences diff --git a/app/src/main/java/com/eatssu/android/data/usecase/ReissueTokenUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/ReissueTokenUseCase.kt similarity index 91% rename from app/src/main/java/com/eatssu/android/data/usecase/ReissueTokenUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/ReissueTokenUseCase.kt index 94695c4f..4d1b7956 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/ReissueTokenUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/ReissueTokenUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import com.eatssu.android.base.BaseResponse import com.eatssu.android.data.dto.response.TokenResponse diff --git a/app/src/main/java/com/eatssu/android/data/usecase/SetAccessTokenUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/SetAccessTokenUseCase.kt similarity index 91% rename from app/src/main/java/com/eatssu/android/data/usecase/SetAccessTokenUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/SetAccessTokenUseCase.kt index 2c5e06b4..39d3b0f8 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/SetAccessTokenUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/SetAccessTokenUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import android.content.Context import com.eatssu.android.util.MySharedPreferences diff --git a/app/src/main/java/com/eatssu/android/data/usecase/SetRefreshTokenUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/SetRefreshTokenUseCase.kt similarity index 91% rename from app/src/main/java/com/eatssu/android/data/usecase/SetRefreshTokenUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/SetRefreshTokenUseCase.kt index d8863c33..6e5a46e8 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/SetRefreshTokenUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/SetRefreshTokenUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import android.content.Context import com.eatssu.android.util.MySharedPreferences diff --git a/app/src/main/java/com/eatssu/android/data/usecase/SetUserEmailUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/SetUserEmailUseCase.kt similarity index 89% rename from app/src/main/java/com/eatssu/android/data/usecase/SetUserEmailUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/SetUserEmailUseCase.kt index 2e27b2ae..d4dce577 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/SetUserEmailUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/SetUserEmailUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import android.content.Context import com.eatssu.android.util.MySharedPreferences diff --git a/app/src/main/java/com/eatssu/android/data/usecase/SetUserNameUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/SetUserNameUseCase.kt similarity index 95% rename from app/src/main/java/com/eatssu/android/data/usecase/SetUserNameUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/SetUserNameUseCase.kt index 18e80ca7..694e265d 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/SetUserNameUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/SetUserNameUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import android.content.Context import com.eatssu.android.base.BaseResponse diff --git a/app/src/main/java/com/eatssu/android/data/usecase/SignOutUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/SignOutUseCase.kt similarity index 88% rename from app/src/main/java/com/eatssu/android/data/usecase/SignOutUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/SignOutUseCase.kt index 01fa506b..70deb45b 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/SignOutUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/SignOutUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import com.eatssu.android.base.BaseResponse import com.eatssu.android.data.repository.UserRepository diff --git a/app/src/main/java/com/eatssu/android/data/usecase/ValidateUserNameUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/auth/ValidateUserNameUseCase.kt similarity index 89% rename from app/src/main/java/com/eatssu/android/data/usecase/ValidateUserNameUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/auth/ValidateUserNameUseCase.kt index b84d9063..945807c2 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/ValidateUserNameUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/auth/ValidateUserNameUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.auth import com.eatssu.android.base.BaseResponse import com.eatssu.android.data.repository.UserRepository diff --git a/app/src/main/java/com/eatssu/android/data/usecase/menu/GetMenuNameListOfMealUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/menu/GetMenuNameListOfMealUseCase.kt new file mode 100644 index 00000000..a006eb71 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/data/usecase/menu/GetMenuNameListOfMealUseCase.kt @@ -0,0 +1,14 @@ +package com.eatssu.android.data.usecase.menu + +import com.eatssu.android.base.BaseResponse +import com.eatssu.android.data.dto.response.MenuOfMealResponse +import com.eatssu.android.data.repository.MealRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetMenuNameListOfMealUseCase @Inject constructor( + private val mealRepository: MealRepository, +) { + suspend operator fun invoke(menuId: Long): Flow> = + mealRepository.getMenuInfoByMealId(menuId) +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/review/DeleteReviewUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/review/DeleteReviewUseCase.kt new file mode 100644 index 00000000..2cc85a07 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/data/usecase/review/DeleteReviewUseCase.kt @@ -0,0 +1,13 @@ +package com.eatssu.android.data.usecase.review + +import com.eatssu.android.base.BaseResponse +import com.eatssu.android.data.repository.ReviewRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class DeleteReviewUseCase @Inject constructor( + private val reviewRepository: ReviewRepository, +) { + suspend operator fun invoke(reviewId: Long): Flow> = + reviewRepository.deleteReview(reviewId) +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/review/GetImageUrlUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/review/GetImageUrlUseCase.kt new file mode 100644 index 00000000..17fdad55 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/data/usecase/review/GetImageUrlUseCase.kt @@ -0,0 +1,17 @@ +package com.eatssu.android.data.usecase.review + +import com.eatssu.android.base.BaseResponse +import com.eatssu.android.data.dto.response.ImageResponse +import com.eatssu.android.data.repository.ReviewRepository +import kotlinx.coroutines.flow.Flow +import okhttp3.MultipartBody +import javax.inject.Inject + +class GetImageUrlUseCase @Inject constructor( + private val reviewRepository: ReviewRepository, +) { + suspend operator fun invoke( + image: MultipartBody.Part, + ): Flow> = + reviewRepository.getImageString(image) +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/review/GetMealReviewInfoUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/review/GetMealReviewInfoUseCase.kt new file mode 100644 index 00000000..41e1f4e6 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/data/usecase/review/GetMealReviewInfoUseCase.kt @@ -0,0 +1,14 @@ +package com.eatssu.android.data.usecase.review + +import com.eatssu.android.base.BaseResponse +import com.eatssu.android.data.dto.response.GetMealReviewInfoResponse +import com.eatssu.android.data.repository.ReviewRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetMealReviewInfoUseCase @Inject constructor( + private val reviewRepository: ReviewRepository, +) { + suspend operator fun invoke(mealId: Long): Flow> = + reviewRepository.getMealReviewInfo(mealId) +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/review/GetMealReviewListUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/review/GetMealReviewListUseCase.kt new file mode 100644 index 00000000..05c487b6 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/data/usecase/review/GetMealReviewListUseCase.kt @@ -0,0 +1,17 @@ +package com.eatssu.android.data.usecase.review + +import com.eatssu.android.base.BaseResponse +import com.eatssu.android.data.dto.response.GetReviewListResponse +import com.eatssu.android.data.enums.MenuType +import com.eatssu.android.data.repository.ReviewRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetMealReviewListUseCase @Inject constructor( + private val reviewRepository: ReviewRepository, +) { + suspend operator fun invoke( + mealId: Long?, + ): Flow> = + reviewRepository.getReviewList(MenuType.VARIABLE.toString(), mealId, 0) +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/review/GetMenuReviewInfoUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/review/GetMenuReviewInfoUseCase.kt new file mode 100644 index 00000000..1bb65eda --- /dev/null +++ b/app/src/main/java/com/eatssu/android/data/usecase/review/GetMenuReviewInfoUseCase.kt @@ -0,0 +1,14 @@ +package com.eatssu.android.data.usecase.review + +import com.eatssu.android.base.BaseResponse +import com.eatssu.android.data.dto.response.GetMenuReviewInfoResponse +import com.eatssu.android.data.repository.ReviewRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetMenuReviewInfoUseCase @Inject constructor( + private val reviewRepository: ReviewRepository, +) { + suspend operator fun invoke(menuId: Long): Flow> = + reviewRepository.getMenuReviewInfo(menuId) +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/review/GetMenuReviewListUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/review/GetMenuReviewListUseCase.kt new file mode 100644 index 00000000..d6c47249 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/data/usecase/review/GetMenuReviewListUseCase.kt @@ -0,0 +1,17 @@ +package com.eatssu.android.data.usecase.review + +import com.eatssu.android.base.BaseResponse +import com.eatssu.android.data.dto.response.GetReviewListResponse +import com.eatssu.android.data.enums.MenuType +import com.eatssu.android.data.repository.ReviewRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetMenuReviewListUseCase @Inject constructor( + private val reviewRepository: ReviewRepository, +) { + suspend operator fun invoke( + menuId: Long?, + ): Flow> = + reviewRepository.getReviewList(MenuType.FIXED.toString(), 0, menuId) +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/review/ModifyReviewUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/review/ModifyReviewUseCase.kt new file mode 100644 index 00000000..5dcf07ee --- /dev/null +++ b/app/src/main/java/com/eatssu/android/data/usecase/review/ModifyReviewUseCase.kt @@ -0,0 +1,17 @@ +package com.eatssu.android.data.usecase.review + +import com.eatssu.android.base.BaseResponse +import com.eatssu.android.data.dto.request.ModifyReviewRequest +import com.eatssu.android.data.repository.ReviewRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class ModifyReviewUseCase @Inject constructor( + private val reviewRepository: ReviewRepository, +) { + suspend operator fun invoke( + reviewId: Long, + body: ModifyReviewRequest, + ): Flow> = + reviewRepository.modifyReview(reviewId, body) +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/PostReportUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/review/PostReportUseCase.kt similarity index 90% rename from app/src/main/java/com/eatssu/android/data/usecase/PostReportUseCase.kt rename to app/src/main/java/com/eatssu/android/data/usecase/review/PostReportUseCase.kt index 5406b461..6f138d82 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/PostReportUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/review/PostReportUseCase.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.data.usecase +package com.eatssu.android.data.usecase.review import com.eatssu.android.base.BaseResponse import com.eatssu.android.data.dto.request.ReportRequest diff --git a/app/src/main/java/com/eatssu/android/data/usecase/review/WriteReviewUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/review/WriteReviewUseCase.kt new file mode 100644 index 00000000..280589fc --- /dev/null +++ b/app/src/main/java/com/eatssu/android/data/usecase/review/WriteReviewUseCase.kt @@ -0,0 +1,14 @@ +package com.eatssu.android.data.usecase.review + +import com.eatssu.android.base.BaseResponse +import com.eatssu.android.data.dto.request.WriteReviewRequest +import com.eatssu.android.data.repository.ReviewRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class WriteReviewUseCase @Inject constructor( + private val reviewRepository: ReviewRepository, +) { + suspend operator fun invoke(menuId: Long, body: WriteReviewRequest): Flow> = + reviewRepository.writeReview(menuId, body) +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/di/DataModule.kt b/app/src/main/java/com/eatssu/android/di/DataModule.kt index ee24d5f7..67133090 100644 --- a/app/src/main/java/com/eatssu/android/di/DataModule.kt +++ b/app/src/main/java/com/eatssu/android/di/DataModule.kt @@ -1,16 +1,20 @@ package com.eatssu.android.di +import com.eatssu.android.data.repository.MealRepository +import com.eatssu.android.data.repository.MealRepositoryImpl import com.eatssu.android.data.repository.OauthRepository import com.eatssu.android.data.repository.OauthRepositoryImpl import com.eatssu.android.data.repository.ReportRepository import com.eatssu.android.data.repository.ReportRepositoryImpl +import com.eatssu.android.data.repository.ReviewRepository import com.eatssu.android.data.repository.UserRepository import com.eatssu.android.data.repository.UserRepositoryImpl import dagger.Binds import dagger.Module import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import com.eatssu.android.data.repository.ReviewRepositoryImpl as ReviewRepositoryImpl1 @Module @InstallIn(SingletonComponent::class) @@ -31,4 +35,13 @@ abstract class DataModule { reportRepositoryImpl: ReportRepositoryImpl, ): ReportRepository + @Binds + internal abstract fun bindsReviewRepository( + reviewRepositoryImpl: ReviewRepositoryImpl1, + ): ReviewRepository + + @Binds + internal abstract fun bindsMealRepository( + mealRepositoryImpl: MealRepositoryImpl, + ): MealRepository } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/di/NetworkModule.kt b/app/src/main/java/com/eatssu/android/di/NetworkModule.kt index 79e283b7..2f513849 100644 --- a/app/src/main/java/com/eatssu/android/di/NetworkModule.kt +++ b/app/src/main/java/com/eatssu/android/di/NetworkModule.kt @@ -3,8 +3,10 @@ package com.eatssu.android.di import com.eatssu.android.BuildConfig import com.eatssu.android.BuildConfig.BASE_URL +import com.eatssu.android.data.service.MealService import com.eatssu.android.data.service.OauthService import com.eatssu.android.data.service.ReportService +import com.eatssu.android.data.service.ReviewService import com.eatssu.android.data.service.UserService import com.eatssu.android.di.network.TokenInterceptor import dagger.Module @@ -81,4 +83,17 @@ object NetworkModule { fun provideReportService(retrofit: Retrofit): ReportService { return retrofit.create(ReportService::class.java) } + + @Provides + @Singleton + fun provideReviewService(retrofit: Retrofit): ReviewService { + return retrofit.create(ReviewService::class.java) + } + + @Provides + @Singleton + fun provideMealService(retrofit: Retrofit): MealService { + return retrofit.create(MealService::class.java) + } + } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/di/network/TokenInterceptor.kt b/app/src/main/java/com/eatssu/android/di/network/TokenInterceptor.kt index d1583cc6..6d7d25a3 100644 --- a/app/src/main/java/com/eatssu/android/di/network/TokenInterceptor.kt +++ b/app/src/main/java/com/eatssu/android/di/network/TokenInterceptor.kt @@ -9,11 +9,11 @@ import android.widget.Toast import com.eatssu.android.BuildConfig.BASE_URL import com.eatssu.android.base.BaseResponse import com.eatssu.android.data.dto.response.TokenResponse -import com.eatssu.android.data.usecase.GetAccessTokenUseCase -import com.eatssu.android.data.usecase.GetRefreshTokenUseCase -import com.eatssu.android.data.usecase.LogoutUseCase -import com.eatssu.android.data.usecase.SetAccessTokenUseCase -import com.eatssu.android.data.usecase.SetRefreshTokenUseCase +import com.eatssu.android.data.usecase.auth.GetAccessTokenUseCase +import com.eatssu.android.data.usecase.auth.GetRefreshTokenUseCase +import com.eatssu.android.data.usecase.auth.LogoutUseCase +import com.eatssu.android.data.usecase.auth.SetAccessTokenUseCase +import com.eatssu.android.data.usecase.auth.SetRefreshTokenUseCase import com.eatssu.android.ui.login.LoginActivity import com.google.gson.Gson import com.google.gson.reflect.TypeToken @@ -37,15 +37,19 @@ class TokenInterceptor @Inject constructor( ) : Interceptor { companion object { + const val TAG = "TokenInterceptor" + val EXCEPT_LIST = listOf( "/oauths/reissue/token", "/oauths/kakao", ) - - const val TAG = "TokenInterceptor" +// val MULTI_PART = "/reviews/upload/image" private const val CODE_TOKEN_EXPIRED = 401 private const val HEADER_AUTHORIZATION = "Authorization" + private const val HEADER_CONTENT_TYPE = "Content-Type" + private const val HEADER_ACCEPT = "accept" + private const val HEADER_ACCESS_TOKEN = "X-ACCESS-AUTH" private const val HEADER_REFRESH_TOKEN = "X-REFRESH-AUTH" } @@ -60,16 +64,23 @@ class TokenInterceptor @Inject constructor( val originalRequest = chain.request() val request = chain.request().newBuilder().apply { if (EXCEPT_LIST.none { originalRequest.url.encodedPath.endsWith(it) }) { - addHeader("accept", "application/hal+json") - addHeader("Content-Type", "application/json") + addHeader(HEADER_ACCEPT, "application/hal+json") + addHeader(HEADER_CONTENT_TYPE, "application/json") addHeader(HEADER_AUTHORIZATION, "Bearer $accessToken") } +// else if (MULTI_PART.none { originalRequest.url.encodedPath.endsWith(it) }) { +// Timber.d("멀티파트 시작!") +// addHeader(HEADER_ACCEPT, "application/hal+json") +// removeHeader("Content-Type") +// addHeader("Content-Type", "multipart/form-data") +// addHeader(HEADER_AUTHORIZATION, "Bearer $accessToken") +// } }.build() val response = chain.proceed(request) if (response.code == 401) { - Timber.d("토큰 퉤퉤") + Timber.d("토큰 401") response.close() try { @@ -79,7 +90,7 @@ class TokenInterceptor @Inject constructor( .addHeader(HEADER_AUTHORIZATION, "Bearer $refreshToken") .build() - Timber.d("재발급 중") + Timber.d("토큰 재발급 중") val refreshTokenResponse = chain.proceed(refreshTokenRequest) Timber.d("refreshTokenResponse : $refreshTokenResponse") @@ -102,10 +113,12 @@ class TokenInterceptor @Inject constructor( val newRequest = originalRequest.newAuthBuilder().build() return chain.proceed(newRequest) } else { - /* - refreshTokenResponse : Response{protocol=http/1.1, code=401, message=, url=https://prod.eat-ssu.shop/oauths/reissue/token} - 위 상황에서도 로그아웃 - **리프레쉬도 상한 상태 + /** + * + * + * refreshTokenResponse : Response{protocol=http/1.1, code=401, message=, url=https://prod.eat-ssu.shop/oauths/reissue/token} + * 위 상황에서도 로그아웃 + * 리프레쉬도 상한 상태 */ runBlocking { logoutUseCase() } Timber.e("재발급에서의 401") diff --git a/app/src/main/java/com/eatssu/android/ui/login/IntroViewModel.kt b/app/src/main/java/com/eatssu/android/ui/login/IntroViewModel.kt index 1556a1cd..bd3e9ab4 100644 --- a/app/src/main/java/com/eatssu/android/ui/login/IntroViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/login/IntroViewModel.kt @@ -2,7 +2,7 @@ package com.eatssu.android.ui.login import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.eatssu.android.data.usecase.GetAccessTokenUseCase +import com.eatssu.android.data.usecase.auth.GetAccessTokenUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow diff --git a/app/src/main/java/com/eatssu/android/ui/login/LoginViewModel.kt b/app/src/main/java/com/eatssu/android/ui/login/LoginViewModel.kt index 435399ec..425e32da 100644 --- a/app/src/main/java/com/eatssu/android/ui/login/LoginViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/login/LoginViewModel.kt @@ -5,10 +5,10 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.eatssu.android.R import com.eatssu.android.data.dto.request.LoginWithKakaoRequest -import com.eatssu.android.data.usecase.LoginUseCase -import com.eatssu.android.data.usecase.SetAccessTokenUseCase -import com.eatssu.android.data.usecase.SetRefreshTokenUseCase -import com.eatssu.android.data.usecase.SetUserEmailUseCase +import com.eatssu.android.data.usecase.auth.LoginUseCase +import com.eatssu.android.data.usecase.auth.SetAccessTokenUseCase +import com.eatssu.android.data.usecase.auth.SetRefreshTokenUseCase +import com.eatssu.android.data.usecase.auth.SetUserEmailUseCase import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.MutableStateFlow diff --git a/app/src/main/java/com/eatssu/android/ui/main/MainViewModel.kt b/app/src/main/java/com/eatssu/android/ui/main/MainViewModel.kt index 07acdaad..7738df8f 100644 --- a/app/src/main/java/com/eatssu/android/ui/main/MainViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/main/MainViewModel.kt @@ -4,7 +4,7 @@ import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.eatssu.android.R -import com.eatssu.android.data.usecase.GetUserInfoUseCase +import com.eatssu.android.data.usecase.auth.GetUserInfoUseCase import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.MutableStateFlow diff --git a/app/src/main/java/com/eatssu/android/ui/main/menu/MenuViewModel.kt b/app/src/main/java/com/eatssu/android/ui/main/menu/MenuViewModel.kt index 8d2b47eb..5429a7c8 100644 --- a/app/src/main/java/com/eatssu/android/ui/main/menu/MenuViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/main/menu/MenuViewModel.kt @@ -8,8 +8,6 @@ import androidx.lifecycle.viewModelScope import com.eatssu.android.base.BaseResponse import com.eatssu.android.data.dto.response.GetFixedMenuResponse import com.eatssu.android.data.dto.response.GetMealResponse -import com.eatssu.android.data.dto.response.MenuOfMealResponse -import com.eatssu.android.data.dto.response.asMenuOfMeal import com.eatssu.android.data.enums.Restaurant import com.eatssu.android.data.enums.Time import com.eatssu.android.data.model.MenuMini @@ -18,7 +16,6 @@ import com.eatssu.android.data.service.MenuService import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import retrofit2.Call import retrofit2.Callback @@ -134,36 +131,36 @@ class MenuViewModel( } } - fun findMenuItemByMealId(mealId: Long) { - viewModelScope.launch { - mealService.getMenuInfoByMealId(mealId) - .enqueue(object : Callback> { - override fun onResponse( - call: Call>, - response: Response>, - ) { - if (response.isSuccessful) { - val data = response.body()?.result - Log.d("post", "onResponse 성공" + response.body()) - _uiState.update { - it.copy( - menuOfMeal = response.body()?.result?.asMenuOfMeal() - ) - } - } else { - Log.d("post", "onResponse 실패") - } - } - - override fun onFailure( - call: Call>, - t: Throwable, - ) { - Log.d("post", "onFailure 에러: ${t.message}") - } - }) - } - } +// fun findMenuItemByMealId(mealId: Long) { +// viewModelScope.launch { +// mealService.getMenuInfoByMealId(mealId) +// .enqueue(object : Callback> { +// override fun onResponse( +// call: Call>, +// response: Response>, +// ) { +// if (response.isSuccessful) { +// val data = response.body()?.result +// Log.d("post", "onResponse 성공" + response.body()) +// _uiState.update { +// it.copy( +// menuOfMeal = response.body()?.result?.asMenuOfMeal() +// ) +// } +// } else { +// Log.d("post", "onResponse 실패") +// } +// } +// +// override fun onFailure( +// call: Call>, +// t: Throwable, +// ) { +// Log.d("post", "onFailure 에러: ${t.message}") +// } +// }) +// } +// } } data class MenuState( diff --git a/app/src/main/java/com/eatssu/android/ui/mypage/MyPageViewModel.kt b/app/src/main/java/com/eatssu/android/ui/mypage/MyPageViewModel.kt index 923213e3..4cc4cb18 100644 --- a/app/src/main/java/com/eatssu/android/ui/mypage/MyPageViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/mypage/MyPageViewModel.kt @@ -1,18 +1,17 @@ package com.eatssu.android.ui.mypage -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.eatssu.android.BuildConfig import com.eatssu.android.data.repository.PreferencesRepository -import com.eatssu.android.data.usecase.AlarmUseCase -import com.eatssu.android.data.usecase.GetDailyNotificationStatusUseCase -import com.eatssu.android.data.usecase.GetUserInfoUseCase -import com.eatssu.android.data.usecase.LogoutUseCase -import com.eatssu.android.data.usecase.SetAccessTokenUseCase -import com.eatssu.android.data.usecase.SetDailyNotificationStatusUseCase -import com.eatssu.android.data.usecase.SetRefreshTokenUseCase -import com.eatssu.android.data.usecase.SignOutUseCase +import com.eatssu.android.data.usecase.alarm.AlarmUseCase +import com.eatssu.android.data.usecase.alarm.GetDailyNotificationStatusUseCase +import com.eatssu.android.data.usecase.alarm.SetDailyNotificationStatusUseCase +import com.eatssu.android.data.usecase.auth.GetUserInfoUseCase +import com.eatssu.android.data.usecase.auth.LogoutUseCase +import com.eatssu.android.data.usecase.auth.SetAccessTokenUseCase +import com.eatssu.android.data.usecase.auth.SetRefreshTokenUseCase +import com.eatssu.android.data.usecase.auth.SignOutUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -23,6 +22,7 @@ import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import timber.log.Timber import javax.inject.Inject @HiltViewModel @@ -70,9 +70,9 @@ class MyPageViewModel @Inject constructor( _uiState.update { it.copy(loading = false, error = true) } }.catch { e -> _uiState.update { it.copy(error = true, toastMessage = "정보를 불러올 수 없습니다.") } - Log.e(TAG, e.toString()) + Timber.e(e.toString()) }.collectLatest { result -> - Log.d(TAG, result.toString()) + Timber.d(result.toString()) result.result?.apply { if (this.nickname.isNullOrBlank()) { _uiState.update { @@ -121,10 +121,9 @@ class MyPageViewModel @Inject constructor( _uiState.update { it.copy(loading = false, error = true) } }.catch { e -> _uiState.update { it.copy(error = true, toastMessage = "정보를 불러올 수 없습니다.") } - Log.d(TAG, e.toString()) - + Timber.e(e.toString()) }.collectLatest { result -> - Log.d(TAG, result.toString()) + Timber.d(result.toString()) if (result.result == true) { logoutUseCase() _uiState.update { diff --git a/app/src/main/java/com/eatssu/android/ui/mypage/SignOutViewModel.kt b/app/src/main/java/com/eatssu/android/ui/mypage/SignOutViewModel.kt index 91c76fbe..d4af75cc 100644 --- a/app/src/main/java/com/eatssu/android/ui/mypage/SignOutViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/mypage/SignOutViewModel.kt @@ -3,11 +3,11 @@ package com.eatssu.android.ui.mypage import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.eatssu.android.data.usecase.GetUserInfoUseCase -import com.eatssu.android.data.usecase.LogoutUseCase -import com.eatssu.android.data.usecase.SetAccessTokenUseCase -import com.eatssu.android.data.usecase.SetRefreshTokenUseCase -import com.eatssu.android.data.usecase.SignOutUseCase +import com.eatssu.android.data.usecase.auth.GetUserInfoUseCase +import com.eatssu.android.data.usecase.auth.LogoutUseCase +import com.eatssu.android.data.usecase.auth.SetAccessTokenUseCase +import com.eatssu.android.data.usecase.auth.SetRefreshTokenUseCase +import com.eatssu.android.data.usecase.auth.SignOutUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow diff --git a/app/src/main/java/com/eatssu/android/ui/mypage/myreview/MyReviewAdapter.kt b/app/src/main/java/com/eatssu/android/ui/mypage/myreview/MyReviewAdapter.kt index ba10ef14..e2265bb8 100644 --- a/app/src/main/java/com/eatssu/android/ui/mypage/myreview/MyReviewAdapter.kt +++ b/app/src/main/java/com/eatssu/android/ui/mypage/myreview/MyReviewAdapter.kt @@ -1,7 +1,6 @@ package com.eatssu.android.ui.mypage.myreview import android.content.Intent -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -13,6 +12,7 @@ import com.eatssu.android.data.model.Review import com.eatssu.android.databinding.ItemReviewBinding import com.eatssu.android.ui.review.delete.MyReviewDialogActivity import com.eatssu.android.util.MySharedPreferences +import timber.log.Timber class MyReviewAdapter(private val dataList: List) : @@ -34,7 +34,7 @@ class MyReviewAdapter(private val dataList: List) : if (dataList[position].imgUrl?.isEmpty() == true) { imageView.visibility = View.GONE } else { - Log.d("qwer", "사진 있다") + Timber.d("사진 있다") Glide.with(itemView) .load(dataList[position].imgUrl?.get(0)) .into(imageView) @@ -56,10 +56,13 @@ class MyReviewAdapter(private val dataList: List) : intent.putExtra("amountGrade", dataList[position].amountGrade) intent.putExtra("tasteGrade", dataList[position].tasteGrade) - Log.d("ReviewFixedActivity", "전전:" + dataList[position].reviewId) - Log.d("ReviewFixedActivity", "전전:" + dataList[position].menu) - Log.d("ReviewFixedActivity", "전전:" + dataList[position].content) -//// + Timber.d( + "리뷰 상세 정보 - ID: %d, 메뉴: %s, 내용: %s", + dataList[position].reviewId, + dataList[position].menu, + dataList[position].content + ) + ContextCompat.startActivity(binding.btnDetail.context, intent, null) } } diff --git a/app/src/main/java/com/eatssu/android/ui/mypage/myreview/MyReviewViewModel.kt b/app/src/main/java/com/eatssu/android/ui/mypage/myreview/MyReviewViewModel.kt index 9f846bd7..2ca041e4 100644 --- a/app/src/main/java/com/eatssu/android/ui/mypage/myreview/MyReviewViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/mypage/myreview/MyReviewViewModel.kt @@ -1,11 +1,10 @@ package com.eatssu.android.ui.mypage.myreview -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.eatssu.android.data.dto.response.toReviewList import com.eatssu.android.data.model.Review -import com.eatssu.android.data.usecase.GetMyReviewsUseCase +import com.eatssu.android.data.usecase.auth.GetMyReviewsUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -16,6 +15,7 @@ import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import timber.log.Timber import javax.inject.Inject @HiltViewModel @@ -38,9 +38,9 @@ class MyReviewViewModel @Inject constructor( _uiState.update { it.copy(loading = false, error = true) } }.catch { e -> _uiState.update { it.copy(error = true, toastMessage = "정보를 불러올 수 없습니다.") } - Log.e(TAG, e.toString()) + Timber.e(e.toString()) }.collectLatest { result -> - Log.d(TAG, result.toString()) + Timber.d(result.toString()) result.result?.apply { if (dataList.isEmpty()) { @@ -55,11 +55,6 @@ class MyReviewViewModel @Inject constructor( } } } - - - companion object { - val TAG = "MyReviewViewModel" - } } diff --git a/app/src/main/java/com/eatssu/android/ui/mypage/terms/WebViewActivity.kt b/app/src/main/java/com/eatssu/android/ui/mypage/terms/WebViewActivity.kt index da3ed88e..75cc1b0d 100644 --- a/app/src/main/java/com/eatssu/android/ui/mypage/terms/WebViewActivity.kt +++ b/app/src/main/java/com/eatssu/android/ui/mypage/terms/WebViewActivity.kt @@ -1,17 +1,14 @@ package com.eatssu.android.ui.mypage.terms import android.os.Bundle -import android.util.Log import android.webkit.WebViewClient import com.eatssu.android.base.BaseActivity import com.eatssu.android.databinding.ActivityWebviewBinding +import timber.log.Timber class WebViewActivity : BaseActivity(ActivityWebviewBinding::inflate) { - companion object { - val TAG = "WebViewActivity" - } private var URL = "" private var TITLE = "" @@ -32,7 +29,7 @@ class WebViewActivity : BaseActivity(ActivityWebviewBind TITLE = intent.getStringExtra("TITLE") ?: "" toolbarTitle.text = TITLE - Log.d(TAG, URL + TITLE) + Timber.d(URL + TITLE) if (savedInstanceState != null) restoreState(savedInstanceState) else loadUrl(URL) diff --git a/app/src/main/java/com/eatssu/android/ui/mypage/usernamechange/UserNameChangeViewModel.kt b/app/src/main/java/com/eatssu/android/ui/mypage/usernamechange/UserNameChangeViewModel.kt index 9ea99a02..5bc8c96a 100644 --- a/app/src/main/java/com/eatssu/android/ui/mypage/usernamechange/UserNameChangeViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/mypage/usernamechange/UserNameChangeViewModel.kt @@ -3,9 +3,9 @@ package com.eatssu.android.ui.mypage.usernamechange import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.eatssu.android.data.usecase.GetUserNameUseCase -import com.eatssu.android.data.usecase.SetUserNameUseCase -import com.eatssu.android.data.usecase.ValidateUserNameUseCase +import com.eatssu.android.data.usecase.auth.GetUserNameUseCase +import com.eatssu.android.data.usecase.auth.SetUserNameUseCase +import com.eatssu.android.data.usecase.auth.ValidateUserNameUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -16,6 +16,7 @@ import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import timber.log.Timber import javax.inject.Inject @HiltViewModel @@ -37,7 +38,7 @@ class UserNameChangeViewModel @Inject constructor( _uiState.update { it.copy(loading = false, error = true) } }.catch { e -> _uiState.update { it.copy(error = true, toastMessage = "닉네임 중복 확인에 실패했습니다.") } - Log.e(TAG, e.toString()) + Timber.e(e.toString()) }.collectLatest { result -> if (result.result == true) { _uiState.update { diff --git a/app/src/main/java/com/eatssu/android/ui/review/delete/DeleteViewModel.kt b/app/src/main/java/com/eatssu/android/ui/review/delete/DeleteViewModel.kt index 140585e5..a268efd4 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/delete/DeleteViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/delete/DeleteViewModel.kt @@ -1,62 +1,68 @@ package com.eatssu.android.ui.review.delete -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData +import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.eatssu.android.base.BaseResponse -import com.eatssu.android.data.service.ReviewService -import com.eatssu.android.util.RetrofitImpl -import kotlinx.coroutines.Dispatchers +import com.eatssu.android.R +import com.eatssu.android.data.usecase.review.DeleteReviewUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.onCompletion +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response - -class DeleteViewModel : ViewModel() { - private val _isDone = MutableLiveData() - val isDone: LiveData get() = _isDone - - private val _toastMessage = MutableLiveData() - val toastMessage: LiveData get() = _toastMessage - - fun postData(reviewId: Long) { - val service = RetrofitImpl.retrofit.create(ReviewService::class.java) - - viewModelScope.launch(Dispatchers.IO) { - service.deleteReview(reviewId).enqueue(object : Callback> { - override fun onResponse( - call: Call>, - response: Response>, - ) { - if (response.isSuccessful) { - if (response.code() == 200) { - handleSuccessResponse("삭제가 완료되었습니다.") - } else { - handleErrorResponse("삭제가 실패하였습니다.") - } - } +import timber.log.Timber +import javax.inject.Inject + +@HiltViewModel +class DeleteViewModel @Inject constructor( + private val deleteReviewUseCase: DeleteReviewUseCase, + @ApplicationContext private val context: Context +) : ViewModel() { + + private val _uiState: MutableStateFlow = MutableStateFlow(DeleteState()) + val uiState: StateFlow = _uiState.asStateFlow() + + + fun deleteReview(reviewId: Long) { + viewModelScope.launch { + deleteReviewUseCase(reviewId).onStart { + _uiState.update { it.copy(loading = true) } + }.onCompletion { + _uiState.update { it.copy(loading = false, error = true) } + }.catch { e -> + _uiState.update { + it.copy( + error = true, + toastMessage = context.getString(R.string.delete_not) + ) } + Timber.e(e.toString()) + }.collectLatest { result -> + Timber.d(result.toString()) - override fun onFailure(call: Call>, t: Throwable) { - handleErrorResponse("삭제가 실패하였습니다.") + _uiState.update { + it.copy( + isDeleted = true, + toastMessage = context.getString(R.string.delete_done) + ) } - }) + } } } +} - fun handleSuccessResponse(message: String) { - viewModelScope.launch(Dispatchers.Main) { - _toastMessage.value = message - _isDone.value = true +data class DeleteState( + var loading: Boolean = true, + var error: Boolean = false, - } - } + var toastMessage: String = "", - fun handleErrorResponse(message: String) { - viewModelScope.launch(Dispatchers.Main) { - _toastMessage.value = message - _isDone.value = false - } - } -} \ No newline at end of file + var isDeleted: Boolean = false, + + ) \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/ui/review/delete/MyReviewDialogActivity.kt b/app/src/main/java/com/eatssu/android/ui/review/delete/MyReviewDialogActivity.kt index 514450da..af0253e0 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/delete/MyReviewDialogActivity.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/delete/MyReviewDialogActivity.kt @@ -2,18 +2,25 @@ package com.eatssu.android.ui.review.delete import android.content.Intent import android.os.Bundle -import android.util.Log -import android.widget.Toast +import androidx.activity.viewModels import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import com.eatssu.android.App +import com.eatssu.android.R import com.eatssu.android.databinding.ActivityMyReviewDialogBinding import com.eatssu.android.ui.review.modify.ModifyReviewActivity +import com.eatssu.android.util.extension.showToast +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch +import timber.log.Timber +@AndroidEntryPoint class MyReviewDialogActivity : AppCompatActivity() { private lateinit var binding: ActivityMyReviewDialogBinding - private lateinit var viewModel: DeleteViewModel + + private val deleteViewModel: DeleteViewModel by viewModels() var reviewId = -1L var menu = "" @@ -28,8 +35,6 @@ class MyReviewDialogActivity : AppCompatActivity() { binding = ActivityMyReviewDialogBinding.inflate(layoutInflater) setContentView(binding.root) - viewModel = ViewModelProvider(this).get(DeleteViewModel::class.java) - reviewId = intent.getLongExtra("reviewId", -1L) menu = intent.getStringExtra("menu").toString() content = intent.getStringExtra("content").toString() @@ -37,9 +42,10 @@ class MyReviewDialogActivity : AppCompatActivity() { amountGrade = intent.getIntExtra("amountGrade", -1) tasteGrade = intent.getIntExtra("tasteGrade", -1) - Log.d("ReviewFixedActivity", "전:" + reviewId.toString()) - Log.d("ReviewFixedActivity", "전:" + menu.toString()) - Log.d("ReviewFixedActivity", "전:" + content.toString()) + Timber.d("전:" + reviewId.toString()) + Timber.d("전:" + menu.toString()) + Timber.d("전:" + content.toString()) + Timber.d(reviewId.toString()) binding.btnReviewFix.setOnClickListener { val intent = Intent(this, ModifyReviewActivity::class.java) @@ -56,29 +62,23 @@ class MyReviewDialogActivity : AppCompatActivity() { binding.btnReviewDelete.setOnClickListener { AlertDialog.Builder(this).apply { - setTitle("리뷰 삭제") - setMessage("작성한 리뷰를 삭제하시겠습니까?") + setTitle(R.string.delete) + setMessage(R.string.delete_description) setNegativeButton("취소") { _, _ -> - viewModel.handleErrorResponse("삭제를 취소하였습니다.") + showToast(App.appContext.getString(R.string.delete_undo)) } setPositiveButton("삭제") { _, _ -> - viewModel.postData(reviewId) + deleteViewModel.deleteReview(reviewId) + lifecycleScope.launch { + deleteViewModel.uiState.collectLatest { + if (it.isDeleted) { + finish() + } + } + } } }.create().show() - observeViewModel() - } - } - - private fun observeViewModel() { - viewModel.toastMessage.observe(this, Observer { result -> - Toast.makeText(this@MyReviewDialogActivity, result, Toast.LENGTH_SHORT).show() - }) - - viewModel.isDone.observe(this) { isDone -> - if(isDone) { - finish() - } } } } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/ui/review/list/ReviewActivity.kt b/app/src/main/java/com/eatssu/android/ui/review/list/ReviewActivity.kt index 06b0f04e..75aadbe3 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/list/ReviewActivity.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/list/ReviewActivity.kt @@ -1,39 +1,29 @@ package com.eatssu.android.ui.review.list -import android.app.AlertDialog import android.content.Intent import android.os.Bundle -import android.util.Log import android.view.View -import android.widget.Toast -import androidx.lifecycle.ViewModelProvider +import androidx.activity.viewModels import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import com.eatssu.android.base.BaseActivity import com.eatssu.android.data.enums.MenuType -import com.eatssu.android.data.repository.ReviewRepository -import com.eatssu.android.data.service.ReviewService import com.eatssu.android.databinding.ActivityReviewBinding import com.eatssu.android.ui.review.delete.DeleteViewModel import com.eatssu.android.ui.review.write.ReviewWriteRateActivity import com.eatssu.android.ui.review.write.menu.ReviewWriteMenuActivity -import com.eatssu.android.util.RetrofitImpl.retrofit import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import timber.log.Timber import kotlin.properties.Delegates @AndroidEntryPoint class ReviewActivity : BaseActivity(ActivityReviewBinding::inflate) { -// private val viewModel: ReviewViewModel by viewModels() - - private lateinit var reviewViewModel: ReviewViewModel - private lateinit var deleteViewModel: DeleteViewModel - - private lateinit var reviewService: ReviewService - private lateinit var reviewRepository: ReviewRepository + private val deleteViewModel: DeleteViewModel by viewModels() + private val reviewViewModel: ReviewViewModel by viewModels() private lateinit var menuType: String private var itemId by Delegates.notNull() @@ -46,50 +36,19 @@ class ReviewActivity : super.onCreate(savedInstanceState) toolbarTitle.text = "리뷰" // 툴바 제목 설정 - initViewModel() getIndex() lodeData() bindData() setClickListener() - } - private fun initViewModel() { - reviewService = retrofit.create(ReviewService::class.java) -// binding = DataBindingUtil.setContentView(this, R.layout.activity_main) - - reviewRepository = ReviewRepository(reviewService) - reviewViewModel = - ViewModelProvider( - this, - ReviewViewModelFactory( - reviewService, -// reviewRepository - ) - )[ReviewViewModel::class.java] - - binding.viewModel = reviewViewModel - - deleteViewModel = ViewModelProvider(this).get(DeleteViewModel::class.java) - - } - - private fun lodeData() { - when (menuType) { - "FIXED" -> { - reviewViewModel.loadReviewList(MenuType.FIXED, 0, itemId) - reviewViewModel.loadMenuReviewInfo(itemId) - } + override fun onResume() { + super.onResume() - "VARIABLE" -> { - reviewViewModel.loadReviewList(MenuType.VARIABLE, itemId, 0) - reviewViewModel.loadMealReviewInfo(itemId) - } - else -> { - Log.d("ReviewActivity", "잘못된 식당 정보입니다.") - } - } + //todo 이거 안하면 바로바로 갱신이 안되는디 + lodeData() + bindData() } @@ -99,59 +58,42 @@ class ReviewActivity : itemId = intent.getLongExtra("itemId", 0) itemName = intent.getStringExtra("itemName").toString().replace(Regex("[\\[\\]]"), "") - Log.d("ReviewActivity", "메뉴는 ${itemName}") - Log.d("ReviewActivity", "메뉴는 ${menuType} ${itemId}") + Timber.d("메뉴는 $itemName $menuType $itemId") } - private fun setClickListener() { - when (menuType) { - "FIXED" -> { - binding.btnNextReview.setOnClickListener { - val intent = Intent(this, ReviewWriteRateActivity::class.java) // 인텐트를 생성해줌, - intent.putExtra("itemId", itemId) - intent.putExtra("itemName", itemName) - intent.putExtra("menuType", menuType) - startActivity(intent) - } - } - - "VARIABLE" -> { - binding.btnNextReview.setOnClickListener { - val intent = Intent(this, ReviewWriteMenuActivity::class.java) // 인텐트를 생성해줌, - intent.putExtra("itemId", itemId) - intent.putExtra("menuType", menuType) - startActivity(intent) - } - } + private fun lodeData() { + //Todo 여기서는 메뉴 타입이 뭔지 몰라도 됨. 추상화 해도 됨 - else -> { - Log.d("ReviewActivity", "잘못된 식당 정보입니다.") - } - } + reviewViewModel.loadReview(menuType, itemId) } + + private fun bindData() { lifecycleScope.launch { reviewViewModel.uiState.collectLatest { if (!it.error && !it.loading) { if (it.isEmpty) { - //리뷰 없어도 메뉴명은 있음 + Timber.d("리뷰가 없음") + binding.llNonReview.visibility = View.VISIBLE + binding.rvReview.visibility = View.INVISIBLE + it.reviewInfo?.apply { binding.tvMenu.text = name.replace(Regex("[\\[\\]]"), "") } - Log.d("ReviewActivity", "리뷰가 없음") - binding.llNonReview.visibility = View.VISIBLE - binding.rvReview.visibility = View.INVISIBLE - } else { //리뷰 있다. - - Log.d("ReviewActivity", "리뷰가 있음") + Timber.d("리뷰가 있음") binding.llNonReview.visibility = View.INVISIBLE binding.rvReview.visibility = View.VISIBLE + reviewAdapter = it.reviewList?.let { review -> - ReviewAdapter(review) { reviewId -> delete(reviewId) } + ReviewAdapter(review) { reviewId -> + deleteViewModel.deleteReview( + reviewId + ) + } } binding.rvReview.apply { @@ -160,17 +102,14 @@ class ReviewActivity : setHasFixedSize(true) } - it.reviewInfo?.apply { - binding.tvMenu.text = name.replace(Regex("[\\[\\]]"), "") - Log.d("ReviewActivity", it.reviewInfo.toString()) + Timber.d(it.reviewInfo.toString()) + binding.tvMenu.text = name.replace(Regex("[\\[\\]]"), "") binding.tvReviewNumCount.text = reviewCnt.toString() - binding.tvRate.text = String.format("%.1f", mainRating) - val totalReviewCount = reviewCnt binding.progressBar1.max = totalReviewCount binding.progressBar2.max = totalReviewCount @@ -190,41 +129,30 @@ class ReviewActivity : } } - fun delete(reviewId: Long) { - - AlertDialog.Builder(this).apply { - setTitle("리뷰 삭제") - setMessage("작성한 리뷰를 삭제하시겠습니까?") - setNegativeButton("취소") { _, _ -> - deleteViewModel.handleErrorResponse("삭제를 취소하였습니다.") - } - setPositiveButton("삭제") { _, _ -> - deleteViewModel.postData(reviewId) + private fun setClickListener() { + when (menuType) { + MenuType.FIXED.name -> { + binding.btnNextReview.setOnClickListener { + val intent = Intent(this, ReviewWriteRateActivity::class.java) + intent.putExtra("itemId", itemId) + intent.putExtra("itemName", itemName) + intent.putExtra("menuType", menuType) + startActivity(intent) + } } - }.create().show() - observeViewModel() - //TODO 삭제하고 리뷰리스트 다시 불러오기 - - } + MenuType.VARIABLE.name -> { + binding.btnNextReview.setOnClickListener { + val intent = Intent(this, ReviewWriteMenuActivity::class.java) + intent.putExtra("itemId", itemId) + intent.putExtra("menuType", menuType) + startActivity(intent) + } + } - private fun observeViewModel() { - deleteViewModel.toastMessage.observe(this) { result -> - Toast.makeText(this, result, Toast.LENGTH_SHORT).show() + else -> { + Timber.d("잘못된 식당 정보입니다.") + } } } - - override fun onRestart() { - super.onRestart() - - lodeData() - bindData() - } - - override fun onResume() { - super.onResume() - - lodeData() - bindData() - } } diff --git a/app/src/main/java/com/eatssu/android/ui/review/list/ReviewViewModel.kt b/app/src/main/java/com/eatssu/android/ui/review/list/ReviewViewModel.kt index 36a4d80d..577e16ff 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/list/ReviewViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/list/ReviewViewModel.kt @@ -1,215 +1,231 @@ package com.eatssu.android.ui.review.list -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.eatssu.android.base.BaseResponse -import com.eatssu.android.data.dto.response.GetMealReviewInfoResponse -import com.eatssu.android.data.dto.response.GetMenuReviewInfoResponse -import com.eatssu.android.data.dto.response.GetReviewListResponse import com.eatssu.android.data.dto.response.asReviewInfo import com.eatssu.android.data.dto.response.toReviewList import com.eatssu.android.data.enums.MenuType import com.eatssu.android.data.model.Review import com.eatssu.android.data.model.ReviewInfo -import com.eatssu.android.data.service.ReviewService +import com.eatssu.android.data.usecase.review.GetMealReviewInfoUseCase +import com.eatssu.android.data.usecase.review.GetMealReviewListUseCase +import com.eatssu.android.data.usecase.review.GetMenuReviewInfoUseCase +import com.eatssu.android.data.usecase.review.GetMenuReviewListUseCase +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.onCompletion +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response +import timber.log.Timber +import javax.inject.Inject -//@HiltViewModel -class ReviewViewModel( -//@Inject constructor( - private val reviewService: ReviewService, -// private val reviewRepository: ReviewRepository, +@HiltViewModel +class ReviewViewModel @Inject constructor( + private val getMenuReviewInfoUseCase: GetMenuReviewInfoUseCase, + private val getMenuReviewListUseCase: GetMenuReviewListUseCase, + private val getMealReviewInfoUseCase: GetMealReviewInfoUseCase, + private val getMealReviewListUseCase: GetMealReviewListUseCase, ) : ViewModel() { -// var menuType: MenuType, -// var itemId: Long? = 0, - -// private val _itemState: MutableStateFlow = -// MutableStateFlow(ItemState(MenuType.FIXED, 0)) -// val ItemState: StateFlow = _itemState.asStateFlow() - private val _uiState: MutableStateFlow = MutableStateFlow(ReviewState()) val uiState: StateFlow = _uiState.asStateFlow() - - fun loadMenuReviewInfo( - menuId: Long, + fun loadReview( + menuType: String, + itemId: Long, ) { + when (menuType) { + MenuType.FIXED.name -> { + callMenuReviewInfo(itemId) + callMenuReviewList(itemId) + } + + MenuType.VARIABLE.name -> { + callMealReviewInfo(itemId) + callMealReviewList(itemId) + } + + else -> { + Timber.d("잘못된 식당 정보입니다.") + + } + } + + } + + private fun callMenuReviewInfo(menuId: Long) { viewModelScope.launch { -// reviewRepository.getMenuReviewInfo(menuId) -// .catch { -// _uiState.value.error = true -// } -// .collect { -// _uiState.value.reviewInfo = it.result?.asReviewInfo() -// Log.d("it.result?.asReviewInfo()",it.result.toString()) -// } - - - reviewService.getMenuReviewInfo(menuId) - .enqueue(object : Callback> { - override fun onResponse( - call: Call>, - response: Response>, - ) { - if (response.isSuccessful) { - val data = response.body()?.result!! - - // 정상적으로 통신이 성공된 경우 - Log.d("ReviewViewModel", "onResponse 성공: " + response.body().toString()) - - if (data.mainRating == null) { - _uiState.update { - it.copy( - loading = false, - error = false, - reviewInfo = data.asReviewInfo(), - isEmpty = true - ) - } - } else { - _uiState.update { - it.copy( - loading = false, - error = false, - reviewInfo = data.asReviewInfo(), - isEmpty = false - ) - } - Log.d("ReviewViewModel", "리뷰 있다고") - } - - } else { - // 통신이 실패한 경우(응답코드 3xx, 4xx 등) - Log.d("ReviewViewModel", "onResponse 실패") + getMenuReviewInfoUseCase(menuId).onStart { + _uiState.update { it.copy(loading = true) } + }.onCompletion { + _uiState.update { it.copy(loading = false, error = true) } + }.catch { e -> + _uiState.update { + it.copy( + loading = false, + error = false, + ) + } + Timber.d(e.toString()) + }.collectLatest { result -> + result.result?.apply { + if (mainRating == null) { + _uiState.update { + it.copy( + loading = false, + error = false, + reviewInfo = asReviewInfo(), + isEmpty = true + ) } + } else { + _uiState.update { + it.copy( + loading = false, + error = false, + reviewInfo = asReviewInfo(), + isEmpty = false + ) + } + Timber.d("리뷰 있다") } - - override fun onFailure( - call: Call>, - t: Throwable, - ) { - // 통신 실패 (인터넷 끊킴, 예외 발생 등 시스템적인 이유) - Log.d("ReviewViewModel", "onFailure 에러: " + t.message.toString()) - } - }) - + } + } } } - fun loadMealReviewInfo( + private fun callMealReviewInfo( mealId: Long, ) { viewModelScope.launch { - reviewService.getMealReviewInfo(mealId) - .enqueue(object : Callback> { - override fun onResponse( - call: Call>, - response: Response>, - ) { - if (response.isSuccessful) { - - val data = response.body()?.result!! - // 정상적으로 통신이 성공된 경우 - Log.d("post", "onResponse 성공: " + response.body().toString()) - _uiState.update { - it.copy( - loading = false, - error = false, - reviewInfo = data.asReviewInfo() - ) - } - } else { - // 통신이 실패한 경우(응답코드 3xx, 4xx 등) - Log.d("post", "onResponse 실패") + getMealReviewInfoUseCase(mealId).onStart { + _uiState.update { it.copy(loading = true) } + }.onCompletion { + _uiState.update { it.copy(loading = false, error = true) } + }.catch { e -> + _uiState.update { + it.copy( + loading = false, + error = false, + ) + } + Timber.e(e.toString()) + }.collectLatest { result -> + result.result?.apply { + if (mainRating == null) { + _uiState.update { + it.copy( + loading = false, + error = false, + reviewInfo = asReviewInfo(), + isEmpty = true + ) } + } else { + _uiState.update { + it.copy( + loading = false, + error = false, + reviewInfo = asReviewInfo(), + isEmpty = false + ) + } + Timber.d("리뷰 있다") } - - override fun onFailure( - call: Call>, - t: Throwable, - ) { - // 통신 실패 (인터넷 끊킴, 예외 발생 등 시스템적인 이유) - Log.d("post", "onFailure 에러: " + t.message.toString()) - } - }) + } + } } } - fun loadReviewList( - menuType: MenuType, - mealId: Long?, - menuId: Long?, -// lastReviewId: Long?, -// page: Int?, -// size: Int?, + private fun callMenuReviewList( + itemId: Long, ) { viewModelScope.launch { - - reviewService.getReviewList(menuType.toString(), mealId, menuId) - .enqueue(object : Callback> { - override fun onResponse( - call: Call>, - response: Response>, - ) { - if (response.isSuccessful) { - Log.d("post", "onResponse 성공: " + response.body().toString()) - - val data = response.body()?.result!! - - if (data.numberOfElements == 0) { //리뷰 없어 시방 - _uiState.update { - it.copy( - loading = false, - error = false, - isEmpty = true - ) - } - } else { //리뷰 있음 - _uiState.update { - it.copy( - loading = false, - error = false, - reviewList = data.toReviewList(), - isEmpty = false - ) - } - } - // 정상적으로 통신이 성공된 경우 - - - } else { - // 통신이 실패한 경우(응답코드 3xx, 4xx 등) - Log.d("post", "onResponse 실패") + getMenuReviewListUseCase(itemId).onStart { + _uiState.update { it.copy(loading = true) } + }.onCompletion { + _uiState.update { it.copy(loading = false, error = true) } + }.catch { e -> + _uiState.update { + it.copy( + loading = false, + error = true, + ) + } + Timber.e(e.toString()) + }.collectLatest { result -> + result.result?.apply { + if (numberOfElements == 0) { //리뷰 없음 + _uiState.update { + it.copy( + loading = false, + error = false, + isEmpty = true + ) + } + } else { //리뷰 있음 + _uiState.update { + it.copy( + loading = false, + error = false, + reviewList = this.toReviewList(), + isEmpty = false + ) } } + } + } + } + } - override fun onFailure( - call: Call>, - t: Throwable, - ) { - // 통신 실패 (인터넷 끊킴, 예외 발생 등 시스템적인 이유) - Log.d("post", "onFailure 에러: " + t.message.toString()) + private fun callMealReviewList( + itemId: Long, + ) { + viewModelScope.launch { + getMealReviewListUseCase(itemId).onStart { + _uiState.update { it.copy(loading = true) } + }.onCompletion { + _uiState.update { it.copy(loading = false, error = true) } + }.catch { e -> + _uiState.update { + it.copy( + loading = false, + error = false, + ) + } + Timber.e(e.toString()) + }.collectLatest { result -> + result.result?.apply { + if (numberOfElements == 0) { //리뷰 없음 + _uiState.update { + it.copy( + loading = false, + error = false, + isEmpty = true + ) + } + } else { //리뷰 있음 + _uiState.update { + it.copy( + loading = false, + error = false, + reviewList = this.toReviewList(), + isEmpty = false + ) + } } - }) + } + } } } } -//data class ItemState( -// var menuType: MenuType, -// var itemid: Long, -//) - data class ReviewState( var loading: Boolean = true, var error: Boolean = false, diff --git a/app/src/main/java/com/eatssu/android/ui/review/list/ReviewViewModelFactory.kt b/app/src/main/java/com/eatssu/android/ui/review/list/ReviewViewModelFactory.kt deleted file mode 100644 index 9f2544de..00000000 --- a/app/src/main/java/com/eatssu/android/ui/review/list/ReviewViewModelFactory.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.eatssu.android.ui.review.list - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import com.eatssu.android.data.service.ReviewService - -class ReviewViewModelFactory( - private val reviewService: ReviewService, -// private val repository: ReviewRepository -) : - ViewModelProvider.Factory { - - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(ReviewViewModel::class.java)) { - @Suppress("UNCHECKED_CAST") - return ReviewViewModel(reviewService) as T - } - throw IllegalArgumentException("Unknown ViewModel class") - } -} - diff --git a/app/src/main/java/com/eatssu/android/ui/review/modify/ModifyReviewActivity.kt b/app/src/main/java/com/eatssu/android/ui/review/modify/ModifyReviewActivity.kt index 104edc80..8ea78f80 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/modify/ModifyReviewActivity.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/modify/ModifyReviewActivity.kt @@ -1,18 +1,21 @@ package com.eatssu.android.ui.review.modify import android.os.Bundle -import android.util.Log -import androidx.lifecycle.ViewModelProvider +import androidx.activity.viewModels import androidx.lifecycle.lifecycleScope import com.eatssu.android.base.BaseActivity +import com.eatssu.android.data.dto.request.ModifyReviewRequest import com.eatssu.android.databinding.ActivityFixMenuBinding import com.eatssu.android.util.extension.showToast +import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import timber.log.Timber +@AndroidEntryPoint class ModifyReviewActivity : BaseActivity(ActivityFixMenuBinding::inflate) { - private lateinit var viewModel: ModifyViewModel + private val modifyViewModel: ModifyViewModel by viewModels() private var reviewId = -1L private var menu = "" @@ -22,11 +25,11 @@ class ModifyReviewActivity : BaseActivity(ActivityFixMen private var main = 0 private var amount = 0 private var taste = 0 + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) toolbarTitle.text = "리뷰 수정하기" // 툴바 제목 설정 - initViewModel() getIndex() setData() setOnClickListener() @@ -39,10 +42,6 @@ class ModifyReviewActivity : BaseActivity(ActivityFixMen } } - private fun initViewModel() { - viewModel = ViewModelProvider(this)[ModifyViewModel::class.java] - - } private fun getIndex() { @@ -54,8 +53,8 @@ class ModifyReviewActivity : BaseActivity(ActivityFixMen amount = intent.getIntExtra("amountGrade", 0) taste = intent.getIntExtra("tasteGrade", 0) - Log.d("ReviewFixedActivity", reviewId.toString() + menu) - Log.d("ReviewFixedActivity", content) + Timber.tag("ReviewFixedActivity") + .d("reviewID: %s, menu: %s, content: %s", reviewId.toString(), menu, content) } private fun setData() { @@ -72,23 +71,27 @@ class ModifyReviewActivity : BaseActivity(ActivityFixMen val amountGrade = binding.rbAmount.rating.toInt() val tasteGrade = binding.rbTaste.rating.toInt() - viewModel.modifyMyReview(reviewId, comment, mainGrade, amountGrade, tasteGrade) + modifyViewModel.modifyMyReview( + reviewId, + ModifyReviewRequest(mainGrade, amountGrade, tasteGrade, comment) + ) } private fun observeViewModel() { lifecycleScope.launch { - viewModel.uiState.collectLatest { - if (!it.error && !it.loading) { - if (it.isDone) { - showToast(it.toastMessage) - finish() - } + modifyViewModel.uiState.collectLatest { + if (it.isDone) { + showToast(it.toastMessage) + finish() } + if (it.error) { showToast(it.toastMessage) } } } } + + //Todo 쓰다 뒤로 갔을 때 undo } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/ui/review/modify/ModifyViewModel.kt b/app/src/main/java/com/eatssu/android/ui/review/modify/ModifyViewModel.kt index 9ed7c85e..24aa96a2 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/modify/ModifyViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/modify/ModifyViewModel.kt @@ -2,77 +2,61 @@ package com.eatssu.android.ui.review.modify import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.eatssu.android.base.BaseResponse +import com.eatssu.android.App +import com.eatssu.android.R import com.eatssu.android.data.dto.request.ModifyReviewRequest -import com.eatssu.android.data.service.ReviewService -import com.eatssu.android.util.RetrofitImpl -import kotlinx.coroutines.Dispatchers +import com.eatssu.android.data.usecase.review.ModifyReviewUseCase +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.onCompletion +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response +import timber.log.Timber +import javax.inject.Inject -class ModifyViewModel : ViewModel() { +@HiltViewModel +class ModifyViewModel @Inject constructor( + private val modifyReviewUseCase: ModifyReviewUseCase, +) : ViewModel() { private val _uiState: MutableStateFlow = MutableStateFlow(ModifyState()) val uiState: StateFlow = _uiState.asStateFlow() fun modifyMyReview( reviewId: Long, - comment: String, - mainGrade: Int, - amountGrade: Int, - tasteGrade: Int, + body: ModifyReviewRequest, ) { - val service = RetrofitImpl.retrofit.create(ReviewService::class.java) - - val reviewData = ModifyReviewRequest(mainGrade, amountGrade, tasteGrade, comment) - - viewModelScope.launch(Dispatchers.IO) { - service.modifyReview(reviewId, reviewData) - .enqueue(object : Callback> { - override fun onResponse( - call: Call>, - response: Response>, - ) { - if (response.isSuccessful) { - if (response.code() == 200) { - _uiState.update { - it.copy( - loading = false, - error = false, - isDone = true, - toastMessage = "수정이 완료되었습니다." - ) - } - } else { - _uiState.update { - it.copy( - loading = false, - error = false, - isDone = true, - toastMessage = "수정이 실패하였습니다." - ) - } - } - } + viewModelScope.launch { + modifyReviewUseCase(reviewId, body).onStart { + _uiState.update { it.copy(loading = true) } + }.onCompletion { + _uiState.update { it.copy(loading = false, error = true) } + }.catch { e -> + _uiState.update { + it.copy( + loading = false, + error = false, + isDone = true, + toastMessage = App.appContext.getString(R.string.modify_not) + ) } - - override fun onFailure(call: Call>, t: Throwable) { - _uiState.update { - it.copy( - loading = false, - error = false, - isDone = true, - toastMessage = "수정이 실패하였습니다." - ) - } + Timber.e(e.toString()) + }.collectLatest { result -> + Timber.d(result.toString()) + _uiState.update { + it.copy( + loading = false, + error = false, + isDone = true, + toastMessage = App.appContext.getString(R.string.modify_done) + ) } - }) + } } } } diff --git a/app/src/main/java/com/eatssu/android/ui/review/report/OthersReviewDialogActivity.kt b/app/src/main/java/com/eatssu/android/ui/review/report/OthersReviewDialogActivity.kt index a9e15406..a2dda37e 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/report/OthersReviewDialogActivity.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/report/OthersReviewDialogActivity.kt @@ -2,9 +2,9 @@ package com.eatssu.android.ui.review.report import android.content.Intent import android.os.Bundle -import android.util.Log import androidx.appcompat.app.AppCompatActivity import com.eatssu.android.databinding.ActivityOthersReviewDialogBinding +import timber.log.Timber class OthersReviewDialogActivity : AppCompatActivity() { @@ -29,7 +29,7 @@ class OthersReviewDialogActivity : AppCompatActivity() { intent.putExtra( "reviewId", reviewId ) - Log.d("dialogid", reviewId.toString()) + Timber.d("reviewId $reviewId") startActivity(intent) finish() } diff --git a/app/src/main/java/com/eatssu/android/ui/review/report/ReportViewModel.kt b/app/src/main/java/com/eatssu/android/ui/review/report/ReportViewModel.kt index 870395b1..36dede17 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/report/ReportViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/report/ReportViewModel.kt @@ -4,7 +4,7 @@ import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.eatssu.android.data.dto.request.ReportRequest -import com.eatssu.android.data.usecase.PostReportUseCase +import com.eatssu.android.data.usecase.review.PostReportUseCase import com.eatssu.android.ui.mypage.usernamechange.UserNameChangeViewModel.Companion.TAG import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow diff --git a/app/src/main/java/com/eatssu/android/ui/review/write/ImageViewModel.kt b/app/src/main/java/com/eatssu/android/ui/review/write/ImageViewModel.kt index 2f1ccf9e..ef3dd8c7 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/write/ImageViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/write/ImageViewModel.kt @@ -1,33 +1,36 @@ package com.eatssu.android.ui.review.write -import android.util.Log -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import com.eatssu.android.base.BaseResponse -import com.eatssu.android.data.dto.response.ImageResponse -import com.eatssu.android.data.service.ImageService +import androidx.lifecycle.viewModelScope +import com.eatssu.android.data.usecase.review.GetImageUrlUseCase +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.onCompletion +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MultipartBody import okhttp3.RequestBody.Companion.asRequestBody -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response +import timber.log.Timber import java.io.File +import javax.inject.Inject -class ImageViewModel( - private val imageService: ImageService, +@HiltViewModel +class ImageViewModel +@Inject constructor( + private val getImageUrlUseCase: GetImageUrlUseCase, ) : ViewModel() { - private val _imageUrl = MutableLiveData() - val imageUrl: LiveData get() = _imageUrl + private val _imageUrl: MutableStateFlow = MutableStateFlow("") + val imageUrl: StateFlow get() = _imageUrl - private var _imageFile = MutableLiveData() - val imageFile: LiveData get() = _imageFile + private var _imageFile: MutableStateFlow = MutableStateFlow(null) + val imageFile: StateFlow get() = _imageFile private val _uiState: MutableStateFlow = MutableStateFlow(ImageState()) val uiState: StateFlow = _uiState.asStateFlow() @@ -44,68 +47,39 @@ class ImageViewModel( fun saveS3() { -// val compressImageString = imageFile.value?.let { compressImage(it) } - if (imageFile.value?.exists() == true) { - val requestFile = imageFile.value!!.asRequestBody("image/*".toMediaTypeOrNull()) - val multipart = MultipartBody.Part.createFormData( - "image", - imageFile.value!!.name, - requestFile - ) - - imageService.getImageUrl(multipart).enqueue( - object : Callback> { - override fun onResponse( - call: Call>, - response: Response>, - ) { - if (response.isSuccessful) { - // 정상적으로 통신이 성공된 경우 - _imageUrl.value = response.body()?.result?.url.toString() - Log.d("ImageViewModel", "이미지 변환 완료") + val requestFile = imageFile.value?.asRequestBody("image/*".toMediaTypeOrNull()) + val multipart = requestFile?.let { + MultipartBody.Part.createFormData( + "image", + imageFile.value?.name, + it + ) + } + viewModelScope.launch { + if (multipart != null) { + getImageUrlUseCase(multipart).onStart { + _uiState.update { it.copy(loading = true) } + }.onCompletion { + _uiState.update { it.copy(loading = false, error = true) } + }.catch { e -> + _uiState.update { it.copy(error = true, toastMessage = "이미지 변환에 실패하였습니다.") } + Timber.e(e.toString()) + }.collectLatest { result -> + Timber.d(result.toString()) + result.result?.apply { _uiState.update { it.copy( loading = false, error = false, - isDone = true, - imgUrl = response.body()?.result?.url.toString() - ) - } - } else { - // 통신이 실패한 경우(응답코드 3xx, 4xx 등) - _uiState.update { - it.copy( - loading = false, - error = true, - isDone = false + isImageUploadDone = true, + imgUrl = url.toString() ) } - Log.d( - "ImageViewModel", - "이미지 변환 실패" + response.body()?.code + response.body()?.message - ) - } - } - - override fun onFailure( - call: Call>, - t: Throwable, - ) { - // 통신 실패 (인터넷 끊킴, 예외 발생 등 시스템적인 이유) - Log.d( - "ImageViewModel", - "onFailure 에러: " + t.message.toString() - ) - _uiState.update { - it.copy( - loading = false, - error = true, - isDone = false - ) } } - }) + } + } } } } @@ -114,7 +88,8 @@ class ImageViewModel( data class ImageState( var loading: Boolean = true, var error: Boolean = false, + var toastMessage: String = "", var imgUrl: String = "", - var isDone: Boolean = false, + var isImageUploadDone: Boolean = false, ) \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/ui/review/write/ImageViewModelFactory.kt b/app/src/main/java/com/eatssu/android/ui/review/write/ImageViewModelFactory.kt deleted file mode 100644 index 38e7c67c..00000000 --- a/app/src/main/java/com/eatssu/android/ui/review/write/ImageViewModelFactory.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.eatssu.android.ui.review.write - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import com.eatssu.android.data.service.ImageService - -class ImageViewModelFactory(private val imageService: ImageService) : - ViewModelProvider.Factory { - - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(ImageViewModel::class.java)) { - @Suppress("UNCHECKED_CAST") - return ImageViewModel(imageService) as T - } - throw IllegalArgumentException("Unknown ViewModel class") - } -} - diff --git a/app/src/main/java/com/eatssu/android/ui/review/write/ReviewWriteRateActivity.kt b/app/src/main/java/com/eatssu/android/ui/review/write/ReviewWriteRateActivity.kt index ef5899cf..229fe0d4 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/write/ReviewWriteRateActivity.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/write/ReviewWriteRateActivity.kt @@ -9,57 +9,49 @@ import android.os.Bundle import android.provider.MediaStore import android.text.Editable import android.text.TextWatcher -import android.util.Log import android.view.View import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.viewModels import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import com.bumptech.glide.Glide import com.bumptech.glide.request.RequestOptions import com.eatssu.android.base.BaseActivity -import com.eatssu.android.data.service.ImageService -import com.eatssu.android.data.service.ReviewService import com.eatssu.android.databinding.ActivityReviewWriteRateBinding -import com.eatssu.android.util.RetrofitImpl.mRetrofit -import com.eatssu.android.util.RetrofitImpl.retrofit import com.eatssu.android.util.extension.showToast +import dagger.hilt.android.AndroidEntryPoint import id.zelory.compressor.Compressor import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import timber.log.Timber import java.io.File import java.text.DecimalFormat import kotlin.math.log10 import kotlin.math.pow +@AndroidEntryPoint class ReviewWriteRateActivity : BaseActivity(ActivityReviewWriteRateBinding::inflate) { - private lateinit var uploadReviewViewModel: UploadReviewViewModel - private lateinit var imageviewModel: ImageViewModel - - private lateinit var reviewService: ReviewService - private lateinit var imageService: ImageService - - private val PERMISSION_REQUEST_CODE = 1 + private val viewModel: UploadReviewViewModel by viewModels() + private val imageviewModel: ImageViewModel by viewModels() private var itemId: Long = 0 private lateinit var itemName: String private var comment: String? = "" - private var imageFile: File? = null private var compressedImage: File? = null - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) toolbarTitle.text = "리뷰 남기기" // 툴바 제목 설정 + binding.viewModel = viewModel itemName = intent.getStringExtra("itemName").toString() - Log.d("post", "고정메뉴${itemName}") + Timber.d("고정메뉴 $itemName") itemId = intent.getLongExtra("itemId", -1) @@ -73,49 +65,31 @@ class ReviewWriteRateActivity : setupTextReviewInput() setOnClickListener() - - - imageService = mRetrofit.create(ImageService::class.java) - reviewService = retrofit.create(ReviewService::class.java) - - - uploadReviewViewModel = ViewModelProvider( - this, - ReviewWriteViewModelFactory(reviewService) - )[UploadReviewViewModel::class.java] - imageviewModel = - ViewModelProvider(this, ImageViewModelFactory(imageService))[ImageViewModel::class.java] - - binding.viewModel = uploadReviewViewModel - } fun setOnClickListener() { // 이미지 추가 버튼 클릭 리스너 설정 binding.ibAddPic.setOnClickListener { - Log.d("ReviewWriteRateActivity", "클릭") + Timber.d("클릭") checkPermission() } binding.btnNextReview2.setOnClickListener { if (binding.rbMain.rating.toInt() == 0 || binding.rbAmount.rating.toInt() == 0 || binding.rbTaste.rating.toInt() == 0) { - Toast.makeText(this, "별점을 등록해주세요", Toast.LENGTH_SHORT).show() - return@setOnClickListener + showToast("별점을 등록해주세요") } if ((comment?.trim()?.length ?: 0) < 3) { - Toast.makeText(this, "3자 이상 입력해주세요", Toast.LENGTH_SHORT).show() - return@setOnClickListener + showToast("3자 이상 입력해주세요") } - //파일 업로드가 끝났거나, 파일을 첨부하지 않거나 if (imageFile?.exists() == true) { showToast("리뷰 업로드 중") compressImage() - Log.d("ImageViewMdoel", "s3 시작") + Timber.d("s3 시작") } else { postReview() @@ -133,7 +107,7 @@ class ReviewWriteRateActivity : lifecycleScope.launch { // Default compression compressedImage = Compressor.compress(this@ReviewWriteRateActivity, imageFile) - Log.d("ImageViewModel", "압축 됨+" + (compressedImage?.length()?.div(1024)).toString()) + Timber.d("압축 된 사이즈+" + (compressedImage?.length()?.div(1024)).toString()) setCompressedImage() } } ?: showError("Please choose an image!") @@ -144,17 +118,17 @@ class ReviewWriteRateActivity : } private fun setCompressedImage() { - compressedImage?.let { + compressedImage?.let { it -> imageviewModel.setImageFile(it) imageviewModel.saveS3() //이미지 url 반환 api 호출 lifecycleScope.launch { imageviewModel.uiState.collectLatest { - if (it.isDone) { + if (it.isImageUploadDone) { postReview() } } } - Log.d("Compressor", "Compressed image save in " + getReadableFileSize(it.length())) + Timber.d("Compressed image save in " + getReadableFileSize(it.length())) } } @@ -212,7 +186,7 @@ class ReviewWriteRateActivity : val result = cursor.getString(columnIndex) cursor.close() - Log.d("ReviewWriteRateActivity", result) + Timber.d("realPath: $result") return result } @@ -231,9 +205,9 @@ class ReviewWriteRateActivity : ActivityCompat.requestPermissions( this, arrayOf( Manifest.permission.READ_MEDIA_IMAGES, - ), REQ_GALLERY + ), PERMISSION_REQUEST_CODE ) - Log.d("ReviewWriteRateActivity", "권한 없음") + Timber.e("권한 없음") } else { openGallery() @@ -257,9 +231,9 @@ class ReviewWriteRateActivity : this, arrayOf( Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE - ), REQ_GALLERY + ), PERMISSION_REQUEST_CODE ) - Log.d("ReviewWriteRateActivity", "권한 없음") + Timber.e("권한 없음") } else { openGallery() @@ -280,11 +254,11 @@ class ReviewWriteRateActivity : } private fun requestStoragePermission() { - if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != + if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) { requestPermissions( - arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE), + arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), PERMISSION_REQUEST_CODE ) } @@ -303,6 +277,7 @@ class ReviewWriteRateActivity : }) } + @Deprecated("This method has been deprecated in favor of using the\n {@link OnBackPressedDispatcher} via {@link #getOnBackPressedDispatcher()}.\n The OnBackPressedDispatcher controls how back button events are dispatched\n to one or more {@link OnBackPressedCallback} objects.") override fun onBackPressed() { super.onBackPressed() if (imageFile?.exists() == true) { @@ -316,9 +291,9 @@ class ReviewWriteRateActivity : private fun deleteImage() { - Log.d("ReviewWriteRateActivity", imageFile.toString()) + Timber.d("imageFile: " + imageFile.toString()) if (imageFile?.exists() == true) { - Toast.makeText(this, "이미지가 삭제되었습니다.", Toast.LENGTH_SHORT).show() + showToast("이미지가 삭제되었습니다.") binding.ivImage.setImageDrawable(null) imageFile!!.delete() //file을 날린다. compressedImage?.delete() //file을 날린다. @@ -329,14 +304,14 @@ class ReviewWriteRateActivity : imageviewModel.deleteFile() } else { - Toast.makeText(this, "이미지를 삭제할 수 없습니다.", Toast.LENGTH_SHORT).show() + showToast("이미지를 삭제할 수 없습니다.") } } private fun postReview() { //Todo imageurl을 체크해야하는 이유? - uploadReviewViewModel.setReviewData( + viewModel.setReviewData( itemId, binding.rbMain.rating.toInt(), binding.rbAmount.rating.toInt(), @@ -345,36 +320,29 @@ class ReviewWriteRateActivity : imageviewModel.imageUrl.value ?: "" ) - uploadReviewViewModel.postReview() - Log.d("ReviewWriteRateActivity", "리뷰 전송") + viewModel.postReview() + Timber.d("리뷰 전송") lifecycleScope.launch { - uploadReviewViewModel.uiState.collectLatest { + viewModel.uiState.collectLatest { if (it.error) { - showToast(uploadReviewViewModel.uiState.value.toastMessage) + showToast(viewModel.uiState.value.toastMessage) } if (!it.error && !it.loading && it.isUpload) { - showToast(uploadReviewViewModel.uiState.value.toastMessage) - Log.d("ReviewWriteRateActivity", "리뷰 작성 성공") + showToast(viewModel.uiState.value.toastMessage) + Timber.d("리뷰 작성 성공") finish() } } } - - } companion object { + const val REVIEW_MIN_LENGTH = 10 // 갤러리 권한 요청 - const val REQ_GALLERY = 1 - - // API 호출시 Parameter key값 - const val PARAM_KEY_IMAGE = "image" - const val PARAM_KEY_PRODUCT_ID = "product_id" - const val PARAM_KEY_REVIEW = "review_content" - const val PARAM_KEY_RATING = "rating" + const val PERMISSION_REQUEST_CODE = 1 } } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/ui/review/write/ReviewWriteViewModel.kt b/app/src/main/java/com/eatssu/android/ui/review/write/ReviewWriteViewModel.kt index eb619c59..c6825fe4 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/write/ReviewWriteViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/write/ReviewWriteViewModel.kt @@ -1,22 +1,27 @@ package com.eatssu.android.ui.review.write -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.eatssu.android.base.BaseResponse import com.eatssu.android.data.dto.request.WriteReviewRequest -import com.eatssu.android.data.service.ReviewService +import com.eatssu.android.data.usecase.review.WriteReviewUseCase +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.onCompletion +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response +import timber.log.Timber +import javax.inject.Inject -class UploadReviewViewModel(private val reviewService: ReviewService) : ViewModel() { +@HiltViewModel +class UploadReviewViewModel @Inject constructor( + private val writeReviewUseCase: WriteReviewUseCase, +) : ViewModel() { private val _uiState: MutableStateFlow = MutableStateFlow(UploadReviewState()) @@ -45,59 +50,33 @@ class UploadReviewViewModel(private val reviewService: ReviewService) : ViewMode fun postReview() { viewModelScope.launch { - reviewService.writeReview( + writeReviewUseCase( menuId.value, reviewData.value - ).enqueue(object : Callback> { - override fun onResponse( - call: Call>, - response: Response>, - ) { - if (response.isSuccessful) { - if (response.body()?.isSuccess == true) { - - _uiState.update { - it.copy( - loading = false, - error = false, - toastMessage = "리뷰가 작성되었습니다.", - isUpload = true, - ) - } - - Log.d( - "UploadReviewViewModel", - "onResponse 리뷰 작성 성공: " + response.body().toString() - ) - - } - } else { - // 통신이 실패한 경우(응답코드 3xx, 4xx 등) - _uiState.update { - it.copy( - loading = false, - error = true, - toastMessage = "리뷰 작성에 실패하였습니다.", - isUpload = false, - ) - } - Log.d("UploadReviewViewModel", "onResponse 리뷰 작성 실패") - } + ).onStart { + _uiState.update { it.copy(loading = true) } + }.onCompletion { + _uiState.update { it.copy(loading = false, error = true) } + }.catch { e -> + _uiState.update { + it.copy( + loading = false, + error = true, + toastMessage = "리뷰 작성에 실패하였습니다.", + isUpload = false, + ) } - - override fun onFailure(call: Call>, t: Throwable) { - // 통신 실패 (인터넷 끊킴, 예외 발생 등 시스템적인 이유) - _uiState.update { - it.copy( - loading = false, - error = true, - toastMessage = "리뷰 작성에 실패하였습니다.", - isUpload = false, - ) - } - - Log.d("UploadReviewViewModel", "onFailure 에러: " + t.message.toString()) + Timber.d(e.toString()) + }.collectLatest { result -> + Timber.d(result.toString()) + _uiState.update { + it.copy( + loading = false, + error = false, + toastMessage = "리뷰가 작성되었습니다.", + isUpload = true, + ) } - }) + } } } } diff --git a/app/src/main/java/com/eatssu/android/ui/review/write/ReviewWriteViewModelFactory.kt b/app/src/main/java/com/eatssu/android/ui/review/write/ReviewWriteViewModelFactory.kt deleted file mode 100644 index 40a55abc..00000000 --- a/app/src/main/java/com/eatssu/android/ui/review/write/ReviewWriteViewModelFactory.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.eatssu.android.ui.review.write - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import com.eatssu.android.data.service.ReviewService - -class ReviewWriteViewModelFactory(private val reviewService: ReviewService) : - ViewModelProvider.Factory { - - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(UploadReviewViewModel::class.java)) { - @Suppress("UNCHECKED_CAST") - return UploadReviewViewModel(reviewService) as T - } - throw IllegalArgumentException("Unknown ViewModel class") - } -} - diff --git a/app/src/main/java/com/eatssu/android/ui/review/write/menu/ReviewWriteMenuActivity.kt b/app/src/main/java/com/eatssu/android/ui/review/write/menu/ReviewWriteMenuActivity.kt index 74b50dac..fc268602 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/write/menu/ReviewWriteMenuActivity.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/write/menu/ReviewWriteMenuActivity.kt @@ -3,54 +3,51 @@ package com.eatssu.android.ui.review.write.menu import android.content.Intent import android.os.Build import android.os.Bundle -import android.util.Log +import androidx.activity.viewModels import androidx.annotation.RequiresApi -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import com.eatssu.android.base.BaseActivity -import com.eatssu.android.data.service.MealService import com.eatssu.android.databinding.ActivityReviewWriteMenuBinding import com.eatssu.android.ui.review.write.ReviewWriteRateActivity -import com.eatssu.android.util.RetrofitImpl.retrofit +import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import timber.log.Timber +@AndroidEntryPoint class ReviewWriteMenuActivity : BaseActivity(ActivityReviewWriteMenuBinding::inflate) { + private val viewModel: VariableMenuViewModel by viewModels() + private var mealId: Long = -1 + private lateinit var variableMenuPickAdapter: VariableMenuPickAdapter - private lateinit var viewModel: VariableMenuViewModel - private lateinit var mealService: MealService @RequiresApi(Build.VERSION_CODES.O) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) toolbarTitle.text = "리뷰 남기기" // 툴바 제목 설정 - val mealId = intent.getLongExtra("itemId", -1) - - initViewModel() - bindData(mealId) + getIndex() + lodeData() + bindData() setClickListener() } - - private fun initViewModel() { - mealService = retrofit.create(MealService::class.java) - viewModel = ViewModelProvider( - this, - VariableMenuModelFactory(mealService) - )[VariableMenuViewModel::class.java] + fun getIndex() { + mealId = intent.getLongExtra("itemId", -1) } - private fun bindData(mealId: Long) { + fun lodeData() { viewModel.findMenuItemByMealId(mealId) + } + private fun bindData() { lifecycleScope.launch { viewModel.uiState.collectLatest { if (!it.error && !it.loading) { - Log.d("ReviewWriteMenuActivity", "!!!받은" + it.menuOfMeal.toString()) + Timber.d("받은" + it.menuOfMeal.toString()) variableMenuPickAdapter = VariableMenuPickAdapter(it.menuOfMeal!!) binding.rvMenuPicker.apply { @@ -58,6 +55,8 @@ class ReviewWriteMenuActivity : layoutManager = LinearLayoutManager(this@ReviewWriteMenuActivity) setHasFixedSize(true) } + // 데이터 바인딩이 완료된 후 클릭 리스너 설정 +// setClickListener() } } } @@ -71,7 +70,7 @@ class ReviewWriteMenuActivity : private fun sendNextItem(items: ArrayList>) { for (i in 0 until items.size) { - Log.d("sendNextItem", items.size.toString()) + Timber.d("sendNextItem: " + items.size.toString()) // 현재 아이템을 가져옴 val currentItem = items[i] diff --git a/app/src/main/java/com/eatssu/android/ui/review/write/menu/VariableMenuModelFactory.kt b/app/src/main/java/com/eatssu/android/ui/review/write/menu/VariableMenuModelFactory.kt deleted file mode 100644 index b0724249..00000000 --- a/app/src/main/java/com/eatssu/android/ui/review/write/menu/VariableMenuModelFactory.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.eatssu.android.ui.review.write.menu - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import com.eatssu.android.data.service.MealService - -class VariableMenuModelFactory(private val mealService: MealService) : - ViewModelProvider.Factory { - - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(VariableMenuViewModel::class.java)) { - @Suppress("UNCHECKED_CAST") - return VariableMenuViewModel(mealService) as T - } - throw IllegalArgumentException("Unknown ViewModel class") - } -} - diff --git a/app/src/main/java/com/eatssu/android/ui/review/write/menu/VariableMenuPickAdapter.kt b/app/src/main/java/com/eatssu/android/ui/review/write/menu/VariableMenuPickAdapter.kt index 93eb9309..833356be 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/write/menu/VariableMenuPickAdapter.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/write/menu/VariableMenuPickAdapter.kt @@ -6,7 +6,7 @@ import androidx.recyclerview.widget.RecyclerView import com.eatssu.android.data.model.MenuMini import com.eatssu.android.databinding.ItemMenuPickBinding -class VariableMenuPickAdapter(private val menuList: List) : +class VariableMenuPickAdapter(private val menuList: List?) : RecyclerView.Adapter() { private val checkedItems: ArrayList> = ArrayList() @@ -15,9 +15,9 @@ class VariableMenuPickAdapter(private val menuList: List) : RecyclerView.ViewHolder(binding.root) { fun bind(position: Int) { - val menuItem = menuList[position] + val menuItem = menuList?.get(position) with(binding) { - tvMenuName.text = menuItem.name + tvMenuName.text = menuItem?.name checkBox.isChecked = checkedItems.contains(getItem(position)) checkBox.setOnClickListener { onCheckBoxClick(position) } } @@ -34,11 +34,11 @@ class VariableMenuPickAdapter(private val menuList: List) : holder.bind(position) } - override fun getItemCount(): Int = menuList.size + override fun getItemCount(): Int = menuList?.size ?: 0 - private fun getItem(position: Int): Pair { - val menuItem = menuList[position] - return Pair(menuItem.name, menuItem.id) + private fun getItem(position: Int): Pair { + val menuItem = menuList?.get(position) + return Pair(menuItem?.name, menuItem?.id) } private fun onCheckBoxClick(position: Int) { @@ -46,7 +46,7 @@ class VariableMenuPickAdapter(private val menuList: List) : if (checkedItems.contains(item)) { checkedItems.remove(item) } else { - checkedItems.add(item) + checkedItems.add(item as Pair) } } diff --git a/app/src/main/java/com/eatssu/android/ui/review/write/menu/VariableMenuViewModel.kt b/app/src/main/java/com/eatssu/android/ui/review/write/menu/VariableMenuViewModel.kt index d13842d0..ab623501 100644 --- a/app/src/main/java/com/eatssu/android/ui/review/write/menu/VariableMenuViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/review/write/menu/VariableMenuViewModel.kt @@ -1,63 +1,65 @@ package com.eatssu.android.ui.review.write.menu -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.eatssu.android.base.BaseResponse -import com.eatssu.android.data.dto.response.MenuOfMealResponse -import com.eatssu.android.data.dto.response.asMenuOfMeal +import com.eatssu.android.data.dto.response.toMenuMiniList import com.eatssu.android.data.model.MenuMini -import com.eatssu.android.data.service.MealService +import com.eatssu.android.data.usecase.menu.GetMenuNameListOfMealUseCase +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.onCompletion +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response +import timber.log.Timber +import javax.inject.Inject -class VariableMenuViewModel( - private val mealService: MealService, -) : - ViewModel() { +@HiltViewModel +class VariableMenuViewModel @Inject constructor( + private val getMenuNameListUseCase: GetMenuNameListOfMealUseCase, +) : ViewModel() { private val _uiState: MutableStateFlow = MutableStateFlow(MenuState()) val uiState: StateFlow = _uiState.asStateFlow() - fun findMenuItemByMealId(mealId: Long) { + Timber.d("findMenuItemByMealId: $mealId") viewModelScope.launch { - mealService.getMenuInfoByMealId(mealId) - .enqueue(object : Callback> { - override fun onResponse( - call: Call>, - response: Response>, - ) { - if (response.isSuccessful) { - val data = response.body()?.result - Log.d("post", "onResponse 성공" + response.body()) - _uiState.update { - it.copy( - loading = false, - error = false, - menuOfMeal = response.body()?.result?.asMenuOfMeal() - ) - } - } else { - Log.d("post", "onResponse 실패") - } - } + getMenuNameListUseCase( + mealId + ).onStart { + Timber.d("findMenuItemByMealId: onStart") + + _uiState.update { it.copy(loading = true) } + }.onCompletion { + Timber.d("findMenuItemByMealId: onCompletion") + + _uiState.update { it.copy(loading = false, error = true) } + }.catch { e -> + Timber.d("findMenuItemByMealId: catch $e") - override fun onFailure( - call: Call>, - t: Throwable, - ) { - Log.d("post", "onFailure 에러: ${t.message}") - } - }) + _uiState.update { + it.copy( + loading = false, + error = true, + ) + } + }.collectLatest { result -> + Timber.d("findMenuItemByMealId: ${result.toString()}") + _uiState.update { + it.copy( + loading = false, + error = false, + menuOfMeal = result.result?.toMenuMiniList() + ) + } + } } } } diff --git a/app/src/main/res/layout/activity_my_review_dialog.xml b/app/src/main/res/layout/activity_my_review_dialog.xml index a37d0004..3a8e5f1a 100644 --- a/app/src/main/res/layout/activity_my_review_dialog.xml +++ b/app/src/main/res/layout/activity_my_review_dialog.xml @@ -12,7 +12,7 @@ android:layout_height="wrap_content" android:background="?android:attr/selectableItemBackground" android:gravity="center" - android:text="@string/fix" /> + android:text="@string/modify" /> + android:title="@string/modify" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 233c03ac..599eb145 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -70,8 +70,19 @@ 신고 - 수정하기 - 삭제하기 + + 수정하기 + 리뷰를 수정하시겠습니까? + 리뷰가 수정되었습니다. + 리뷰 수정이 실패하였습니다. + 리뷰 수정을 취소하시겠습니까? + + 리뷰삭제 + 리뷰를 삭제하시겠습니까? + 리뷰가 삭제 되었습니다. + 리뷰 삭제가 실패 하였습니다. + 리뷰 삭제를 취소하시겠습니까? + 작성한 리뷰 아직 작성한 리뷰가 없어요 첫 리뷰를 남겨 주세요!