diff --git a/app/src/main/java/com/ftw/hometerview/di/api/APIModule.kt b/app/src/main/java/com/ftw/hometerview/di/api/APIModule.kt index fc10a3a..c47fc91 100644 --- a/app/src/main/java/com/ftw/hometerview/di/api/APIModule.kt +++ b/app/src/main/java/com/ftw/hometerview/di/api/APIModule.kt @@ -2,6 +2,7 @@ package com.ftw.hometerview.di.api import com.ftw.data.remote.api.BuildingReviewsAPI import com.ftw.data.remote.api.LoginAPI +import com.ftw.data.remote.api.review.ReviewAPI import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -19,6 +20,12 @@ class APIModule { return retrofit.create(LoginAPI::class.java) } + @Provides + @Singleton + fun provideReviewApi(retrofit: Retrofit): ReviewAPI { + return retrofit.create(ReviewAPI::class.java) + } + @Provides @Singleton fun provideBuildingReviewsApi(retrofit: Retrofit): BuildingReviewsAPI { diff --git a/app/src/main/java/com/ftw/hometerview/di/datasource/ReviewDataSourceModule.kt b/app/src/main/java/com/ftw/hometerview/di/datasource/ReviewDataSourceModule.kt new file mode 100644 index 0000000..bd95f89 --- /dev/null +++ b/app/src/main/java/com/ftw/hometerview/di/datasource/ReviewDataSourceModule.kt @@ -0,0 +1,21 @@ +package com.ftw.hometerview.di.datasource + +import com.ftw.data.datasource.review.ReviewDataSource +import com.ftw.data.remote.api.review.ReviewAPI +import com.ftw.data.remote.datasource.review.ReviewRemoteDataSource +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class ReviewDataSourceModule { + + @Provides + @Singleton + fun provideReviewDataSource(api: ReviewAPI): ReviewDataSource { + return ReviewRemoteDataSource(api) + } +} diff --git a/app/src/main/java/com/ftw/hometerview/di/repository/ReviewRepositoryModule.kt b/app/src/main/java/com/ftw/hometerview/di/repository/ReviewRepositoryModule.kt new file mode 100644 index 0000000..21213c6 --- /dev/null +++ b/app/src/main/java/com/ftw/hometerview/di/repository/ReviewRepositoryModule.kt @@ -0,0 +1,21 @@ +package com.ftw.hometerview.di.repository + +import com.ftw.data.datasource.review.ReviewDataSource +import com.ftw.data.repository.review.ReviewRepositoryImpl +import com.ftw.domain.repository.review.ReviewRepository +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class ReviewRepositoryModule { + + @Provides + @Singleton + fun provideReviewRepository(reviewDataSource: ReviewDataSource): ReviewRepository { + return ReviewRepositoryImpl(reviewDataSource) + } +} diff --git a/app/src/main/java/com/ftw/hometerview/di/ui/ActivityViewModelModule.kt b/app/src/main/java/com/ftw/hometerview/di/ui/ActivityViewModelModule.kt index 90087a0..de8ea4e 100644 --- a/app/src/main/java/com/ftw/hometerview/di/ui/ActivityViewModelModule.kt +++ b/app/src/main/java/com/ftw/hometerview/di/ui/ActivityViewModelModule.kt @@ -6,6 +6,7 @@ import com.ftw.domain.usecase.login.LoginUseCase import com.ftw.domain.usecase.review.GetLocationReviewsUseCase import com.ftw.domain.usecase.searchaddressbuilding.GetSearchAddressBuildingUseCase import com.ftw.domain.usecase.myreviews.GetMyReviewsUseCase +import com.ftw.domain.usecase.review.CreateReviewUseCase import com.ftw.hometerview.dispatcher.Dispatcher import com.ftw.hometerview.ui.buildingreview.BuildingReviewViewModel import com.ftw.hometerview.ui.main.MainViewModel @@ -16,6 +17,7 @@ import com.ftw.hometerview.ui.searchcompanyresult.SearchCompanyResultViewModel import com.ftw.hometerview.ui.splash.SplashViewModel import com.ftw.hometerview.ui.updatenickname.UpdateNicknameViewModel import com.ftw.hometerview.ui.myreviews.MyReviewsViewModel +import com.ftw.hometerview.ui.review.CreateReviewViewModel import com.ftw.hometerview.ui.withdrawal.WithdrawalViewModel import dagger.Module import dagger.Provides @@ -127,4 +129,16 @@ class ActivityViewModelModule { dispatcher ) } + + @Provides + @ActivityScoped + fun provideCreateReviewViewModel( + dispatcher: Dispatcher, + createReviewUseCase: CreateReviewUseCase + ): CreateReviewViewModel { + return CreateReviewViewModel( + dispatcher, + createReviewUseCase + ) + } } diff --git a/app/src/main/java/com/ftw/hometerview/di/usecase/LocationReviewUseCaseModule.kt b/app/src/main/java/com/ftw/hometerview/di/usecase/LocationReviewUseCaseModule.kt new file mode 100644 index 0000000..c0c239a --- /dev/null +++ b/app/src/main/java/com/ftw/hometerview/di/usecase/LocationReviewUseCaseModule.kt @@ -0,0 +1,19 @@ +package com.ftw.hometerview.di.usecase + +import com.ftw.domain.usecase.review.GetLocationReviewsUseCase +import com.ftw.domain.usecase.review.GetLocationReviewsUseCaseImpl +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class LocationReviewUseCaseModule { + @Provides + @Singleton + fun provideGetLocationReviewsUseCase(): GetLocationReviewsUseCase { + return GetLocationReviewsUseCaseImpl() + } +} diff --git a/app/src/main/java/com/ftw/hometerview/di/usecase/ReviewUseCaseModule.kt b/app/src/main/java/com/ftw/hometerview/di/usecase/ReviewUseCaseModule.kt index 244fd93..d71aa21 100644 --- a/app/src/main/java/com/ftw/hometerview/di/usecase/ReviewUseCaseModule.kt +++ b/app/src/main/java/com/ftw/hometerview/di/usecase/ReviewUseCaseModule.kt @@ -1,19 +1,18 @@ package com.ftw.hometerview.di.usecase -import com.ftw.domain.usecase.review.GetLocationReviewsUseCase -import com.ftw.domain.usecase.review.GetLocationReviewsUseCaseImpl +import com.ftw.domain.repository.review.ReviewRepository +import com.ftw.domain.usecase.review.CreateReviewUseCase +import com.ftw.domain.usecase.review.CreateReviewUseCaseImpl import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) class ReviewUseCaseModule { @Provides - @Singleton - fun provideGetLocationReviewsUseCase(): GetLocationReviewsUseCase { - return GetLocationReviewsUseCaseImpl() + fun provideCreateReviewUseCase(repository: ReviewRepository): CreateReviewUseCase { + return CreateReviewUseCaseImpl(repository) } } diff --git a/app/src/main/java/com/ftw/hometerview/ui/review/CreateReviewActivity.kt b/app/src/main/java/com/ftw/hometerview/ui/review/CreateReviewActivity.kt index cfb41db..efcf843 100644 --- a/app/src/main/java/com/ftw/hometerview/ui/review/CreateReviewActivity.kt +++ b/app/src/main/java/com/ftw/hometerview/ui/review/CreateReviewActivity.kt @@ -18,6 +18,7 @@ import com.ftw.hometerview.ui.review.second.CreateReviewSecondStepReviewFragment import com.ftw.hometerview.ui.review.third.CreateReviewThirdStepSearchCompanyFragment import dagger.hilt.android.AndroidEntryPoint import java.util.Date +import javax.inject.Inject @AndroidEntryPoint class CreateReviewActivity : @@ -32,6 +33,9 @@ class CreateReviewActivity : fun newIntent(context: Context): Intent = Intent(context, CreateReviewActivity::class.java) } + @Inject + lateinit var viewModel: CreateReviewViewModel + private var review = Review.NONE override fun onCreate(savedInstanceState: Bundle?) { @@ -48,7 +52,7 @@ class CreateReviewActivity : } override fun onClickAddressFromFirstStepAddress(address: String) { - review = review.copy(buildingAddress = address) + viewModel.setAddress(buildingId = "test") addFragment( R.id.fragment_container_view, CreateReviewFirstStepSelectFloorFragment.newInstance(address), @@ -57,7 +61,7 @@ class CreateReviewActivity : } override fun onClickNextFromFirstStepResidentialFloor(address: String, floor: String) { - review = review.copy(buildingAddress = address) + viewModel.setFloor(floor) addFragment( R.id.fragment_container_view, CreateReviewSecondStepReviewFragment.newInstance(), @@ -71,12 +75,7 @@ class CreateReviewActivity : advantage: String, disadvantage: String ) { - review = review.copy( - rating = rating, - leftAt = leftAt, - advantage = advantage, - disadvantage = disadvantage - ) + viewModel.setInfo(rating, leftAt.toString(), advantage, disadvantage) addFragment( R.id.fragment_container_view, CreateReviewThirdStepSearchCompanyFragment.newInstance(), @@ -85,7 +84,9 @@ class CreateReviewActivity : } override fun onClickNextFromThirdStepSearchCompany(company: String) { - review = review.copy(officeLocation = company) + viewModel.setCompanyId("companyId") + viewModel.create() + setResult( Activity.RESULT_OK, Intent().putExtra(CREATE_REVIEW_RESULT_KEY, review.toParcelable()) diff --git a/app/src/main/java/com/ftw/hometerview/ui/review/CreateReviewViewModel.kt b/app/src/main/java/com/ftw/hometerview/ui/review/CreateReviewViewModel.kt new file mode 100644 index 0000000..072a372 --- /dev/null +++ b/app/src/main/java/com/ftw/hometerview/ui/review/CreateReviewViewModel.kt @@ -0,0 +1,60 @@ +package com.ftw.hometerview.ui.review + +import android.util.Log +import com.ftw.domain.usecase.review.CreateReviewUseCase +import com.ftw.hometerview.dispatcher.Dispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.launch + +class CreateReviewViewModel( + private val dispatcher: Dispatcher, + private val createReviewUseCase: CreateReviewUseCase +) { + private var buildingId: String? = null + private var companyId: String? = null + private var period: String? = null + private var rating: Int? = null + private var advantage: String? = null + private var disadvantage: String? = null + private var floor: String? = null + + fun setAddress(buildingId: String) { + this.buildingId = buildingId + } + + fun setFloor(floor: String) { + this.floor = floor + } + + fun setInfo(rating: Int, period: String, advantage: String, disadvantage: String) { + this.rating = rating + this.period = period + this.advantage = advantage + this.disadvantage = disadvantage + } + + fun setCompanyId(companyId: String) { + this.companyId = companyId + } + + fun create() { + CoroutineScope(dispatcher.ui()).launch { + flow { + emit( + createReviewUseCase( + buildingId = buildingId ?: "", + companyId = companyId ?: "", + period = period ?: "", + rating = rating ?: 0, + advantage = advantage ?: "", + disadvantage = disadvantage ?: "", + floor = floor ?: "" + ) + ) + }.collect { + Log.d("CreateReviewViewModel", "completed") + } + } + } +} diff --git a/app/src/main/java/com/ftw/hometerview/ui/review/first/CreateReviewFirstStepInputAddressViewModel.kt b/app/src/main/java/com/ftw/hometerview/ui/review/first/CreateReviewFirstStepInputAddressViewModel.kt index 2728392..55897a2 100644 --- a/app/src/main/java/com/ftw/hometerview/ui/review/first/CreateReviewFirstStepInputAddressViewModel.kt +++ b/app/src/main/java/com/ftw/hometerview/ui/review/first/CreateReviewFirstStepInputAddressViewModel.kt @@ -34,7 +34,7 @@ class CreateReviewFirstStepInputAddressViewModel( address .debounce(500) .transformLatest { address -> - flow>> { + flow { if (address.isNotBlank()) emit(getAddressUseCase(address)) else emit(Result.success(emptyList())) }.collect { result -> diff --git a/app/src/main/res/layout/activity_building_review.xml b/app/src/main/res/layout/activity_building_review.xml index 622f5f6..5d95b53 100644 --- a/app/src/main/res/layout/activity_building_review.xml +++ b/app/src/main/res/layout/activity_building_review.xml @@ -133,7 +133,7 @@ android:layout_marginHorizontal="@dimen/dp_size_14" android:drawablePadding="@dimen/dp_size_6" android:fontFamily="@font/pretendard_regular" - android:text="@{viewModel.building.address.addressWithLoadName}" + android:text="@{viewModel.building.buildingAddress.addressWithLoadName}" android:textColor="@color/gray_800" android:textSize="@dimen/sp_size_14" app:drawableStartCompat="@drawable/icon_discovery" diff --git a/app/src/main/res/layout/list_item_favorite_building.xml b/app/src/main/res/layout/list_item_favorite_building.xml index 3a17512..63f965b 100644 --- a/app/src/main/res/layout/list_item_favorite_building.xml +++ b/app/src/main/res/layout/list_item_favorite_building.xml @@ -134,7 +134,7 @@ android:ellipsize="end" android:fontFamily="@font/pretendard_regular" android:maxLines="1" - android:text="@{item.favoriteBuildings.address.component3()}" + android:text="@{item.favoriteBuildings.buildingAddress.component3()}" android:textColor="@color/gray_600" android:textSize="@dimen/sp_size_12" app:drawableTint="@color/gray_400" diff --git a/data/src/main/java/com/ftw/data/datasource/review/ReviewDataSource.kt b/data/src/main/java/com/ftw/data/datasource/review/ReviewDataSource.kt new file mode 100644 index 0000000..e31ef79 --- /dev/null +++ b/data/src/main/java/com/ftw/data/datasource/review/ReviewDataSource.kt @@ -0,0 +1,13 @@ +package com.ftw.data.datasource.review + +interface ReviewDataSource { + suspend fun create( + buildingId: String, + companyId: String, + period: String, + rating: Int, + advantage: String, + disadvantage: String, + floor: String + ) +} diff --git a/data/src/main/java/com/ftw/data/remote/api/review/ReviewAPI.kt b/data/src/main/java/com/ftw/data/remote/api/review/ReviewAPI.kt new file mode 100644 index 0000000..71ea4db --- /dev/null +++ b/data/src/main/java/com/ftw/data/remote/api/review/ReviewAPI.kt @@ -0,0 +1,14 @@ +package com.ftw.data.remote.api.review + +import com.ftw.data.remote.request.CreateReviewRequest +import com.ftw.data.remote.response.RemoteResponse +import retrofit2.Response +import retrofit2.http.Body +import retrofit2.http.POST + +interface ReviewAPI { + @POST("/api/v1/review") + fun create( + @Body review: CreateReviewRequest + ): Response> +} diff --git a/data/src/main/java/com/ftw/data/remote/datasource/review/ReviewRemoteDataSource.kt b/data/src/main/java/com/ftw/data/remote/datasource/review/ReviewRemoteDataSource.kt new file mode 100644 index 0000000..89a9138 --- /dev/null +++ b/data/src/main/java/com/ftw/data/remote/datasource/review/ReviewRemoteDataSource.kt @@ -0,0 +1,40 @@ +package com.ftw.data.remote.datasource.review + +import com.ftw.data.datasource.review.ReviewDataSource +import com.ftw.data.remote.api.review.ReviewAPI +import com.ftw.data.remote.exception.ResponseException +import com.ftw.data.remote.request.CreateReviewRequest + +class ReviewRemoteDataSource( + private val api: ReviewAPI +) : ReviewDataSource { + override suspend fun create( + buildingId: String, + companyId: String, + period: String, + rating: Int, + advantage: String, + disadvantage: String, + floor: String + ) { + try { + val response = api.create( + CreateReviewRequest( + buildingId, + companyId, + period, + rating, + advantage, + disadvantage, + floor + ) + ) + + if (!response.isSuccessful) { + throw ResponseException() + } + } catch (e: Exception) { + throw e + } + } +} diff --git a/data/src/main/java/com/ftw/data/remote/exception/ResponseException.kt b/data/src/main/java/com/ftw/data/remote/exception/ResponseException.kt index 2914c93..ec17cf6 100644 --- a/data/src/main/java/com/ftw/data/remote/exception/ResponseException.kt +++ b/data/src/main/java/com/ftw/data/remote/exception/ResponseException.kt @@ -1,3 +1,3 @@ package com.ftw.data.remote.exception -class ResponseException(message: String) : RuntimeException(message) +class ResponseException(message: String = "Network Exception") : RuntimeException(message) diff --git a/data/src/main/java/com/ftw/data/remote/request/CreateReviewRequest.kt b/data/src/main/java/com/ftw/data/remote/request/CreateReviewRequest.kt new file mode 100644 index 0000000..46ba485 --- /dev/null +++ b/data/src/main/java/com/ftw/data/remote/request/CreateReviewRequest.kt @@ -0,0 +1,11 @@ +package com.ftw.data.remote.request + +data class CreateReviewRequest( + val buildingId: String, + val companyId: String, + val period: String, + val rating: Int, + val advantage: String, + val disadvantage: String, + val floor: String +) diff --git a/data/src/main/java/com/ftw/data/repository/review/ReviewRepositoryImpl.kt b/data/src/main/java/com/ftw/data/repository/review/ReviewRepositoryImpl.kt new file mode 100644 index 0000000..d673501 --- /dev/null +++ b/data/src/main/java/com/ftw/data/repository/review/ReviewRepositoryImpl.kt @@ -0,0 +1,20 @@ +package com.ftw.data.repository.review + +import com.ftw.data.datasource.review.ReviewDataSource +import com.ftw.domain.repository.review.ReviewRepository + +class ReviewRepositoryImpl( + private val dataSource: ReviewDataSource +) : ReviewRepository { + override suspend fun create( + buildingId: String, + companyId: String, + period: String, + rating: Int, + advantage: String, + disadvantage: String, + floor: String + ) { + dataSource.create(buildingId, companyId, period, rating, advantage, disadvantage, floor) + } +} diff --git a/domain/src/main/java/com/ftw/domain/entity/Building.kt b/domain/src/main/java/com/ftw/domain/entity/Building.kt index 03a80d8..06fe681 100644 --- a/domain/src/main/java/com/ftw/domain/entity/Building.kt +++ b/domain/src/main/java/com/ftw/domain/entity/Building.kt @@ -4,7 +4,7 @@ data class Building( val id: Long, val name: String, val type: BuildingType, - val address: Address, + val buildingAddress: BuildingAddress, val salePrice: Price, val charterPrice: Price, val rating: Int, @@ -15,7 +15,7 @@ data class Building( id = 0, name = "", type = BuildingType.OFFICETEL, - address = Address(0, 0, "", ""), + buildingAddress = BuildingAddress(0, 0, "", ""), salePrice = Price("", "", ""), charterPrice = Price("", "", ""), rating = 0, diff --git a/domain/src/main/java/com/ftw/domain/entity/Address.kt b/domain/src/main/java/com/ftw/domain/entity/BuildingAddress.kt similarity index 84% rename from domain/src/main/java/com/ftw/domain/entity/Address.kt rename to domain/src/main/java/com/ftw/domain/entity/BuildingAddress.kt index 8387cb3..9ffec9d 100644 --- a/domain/src/main/java/com/ftw/domain/entity/Address.kt +++ b/domain/src/main/java/com/ftw/domain/entity/BuildingAddress.kt @@ -1,6 +1,6 @@ package com.ftw.domain.entity -data class Address( +data class BuildingAddress( val longitude: Long, val latitude: Long, val addressWithLoadName: String, diff --git a/domain/src/main/java/com/ftw/domain/entity/FavoriteBuilding.kt b/domain/src/main/java/com/ftw/domain/entity/FavoriteBuilding.kt index c1fc89c..0c0ab1b 100644 --- a/domain/src/main/java/com/ftw/domain/entity/FavoriteBuilding.kt +++ b/domain/src/main/java/com/ftw/domain/entity/FavoriteBuilding.kt @@ -4,7 +4,7 @@ data class FavoriteBuilding( val buildingId: Long, val buildingName: String, val type: BuildingType, - val address: Address, + val buildingAddress: BuildingAddress, val reviewCount: Int, val rating: Double, val favorite: Boolean diff --git a/domain/src/main/java/com/ftw/domain/usecase/buildingreviews/GetBuildingUseCaseImpl.kt b/domain/src/main/java/com/ftw/domain/usecase/buildingreviews/GetBuildingUseCaseImpl.kt index 4787561..84de424 100644 --- a/domain/src/main/java/com/ftw/domain/usecase/buildingreviews/GetBuildingUseCaseImpl.kt +++ b/domain/src/main/java/com/ftw/domain/usecase/buildingreviews/GetBuildingUseCaseImpl.kt @@ -1,6 +1,6 @@ package com.ftw.domain.usecase.buildingreviews -import com.ftw.domain.entity.Address +import com.ftw.domain.entity.BuildingAddress import com.ftw.domain.entity.Building import com.ftw.domain.entity.BuildingType import com.ftw.domain.entity.Price @@ -35,7 +35,7 @@ class GetBuildingUseCaseImpl : GetBuildingUseCase { id = 1, name = "아크로텔 오피스텔", type = BuildingType.OFFICETEL, - address = Address( + buildingAddress = BuildingAddress( longitude = 123, latitude = 123, addressWithLoadName = "인천 남동구 구월남로 125", diff --git a/domain/src/main/java/com/ftw/domain/usecase/favorite/GetFavoriteBuildingsUseCaseImpl.kt b/domain/src/main/java/com/ftw/domain/usecase/favorite/GetFavoriteBuildingsUseCaseImpl.kt index d543e68..622552d 100644 --- a/domain/src/main/java/com/ftw/domain/usecase/favorite/GetFavoriteBuildingsUseCaseImpl.kt +++ b/domain/src/main/java/com/ftw/domain/usecase/favorite/GetFavoriteBuildingsUseCaseImpl.kt @@ -9,7 +9,7 @@ class GetFavoriteBuildingsUseCaseImpl : GetFavoriteBuildingsUseCase { buildingId = 0, buildingName = "아크로텔 오피스텔", type = BuildingType.OFFICETEL, - address = Address(0, 0, "인천 남동구 구월남로 125", ""), + buildingAddress = BuildingAddress(0, 0, "인천 남동구 구월남로 125", ""), reviewCount = 2, rating = 4.0, favorite = true @@ -18,7 +18,7 @@ class GetFavoriteBuildingsUseCaseImpl : GetFavoriteBuildingsUseCase { buildingId = 0, buildingName = "한국 아파트", type = BuildingType.OFFICETEL, - address = Address(0, 0, "성남대로 1226번길 2", ""), + buildingAddress = BuildingAddress(0, 0, "성남대로 1226번길 2", ""), reviewCount = 4, rating = 4.0, favorite = true @@ -27,7 +27,7 @@ class GetFavoriteBuildingsUseCaseImpl : GetFavoriteBuildingsUseCase { buildingId = 0, buildingName = "한빛 삼성 아파트", type = BuildingType.OFFICETEL, - address = Address(0, 0, "서재2길 41-9", ""), + buildingAddress = BuildingAddress(0, 0, "서재2길 41-9", ""), reviewCount = 6, rating = 3.9, favorite = true